From 56f4c39ed3dfd9916adac99e6aad76a9f056a305 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 8 Jun 2017 06:37:01 +0200 Subject: [PATCH 01/26] Fixed api link for omdb --- src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs b/src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs index a3d56fcf..59b8a6a1 100644 --- a/src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs +++ b/src/NadekoBot/Modules/Searches/Commands/OMDB/OmdbProvider.cs @@ -10,7 +10,7 @@ namespace NadekoBot.Modules.Searches.Commands.OMDB { public static class OmdbProvider { - private const string queryUrl = "http://www.omdbapi.com/?t={0}&y=&plot=full&r=json"; + private const string queryUrl = "http://omdbapi.nadekobot.me/?t={0}&y=&plot=full&r=json"; public static async Task FindMovie(string name) { From 31fa8552777b382f47e83984877793522f746561 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 11 Jun 2017 11:44:30 +0200 Subject: [PATCH 02/26] Update help --- src/NadekoBot/Modules/Help/Help.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NadekoBot/Modules/Help/Help.cs b/src/NadekoBot/Modules/Help/Help.cs index 1208260b..e5b7c462 100644 --- a/src/NadekoBot/Modules/Help/Help.cs +++ b/src/NadekoBot/Modules/Help/Help.cs @@ -159,8 +159,8 @@ namespace NadekoBot.Modules.Help public async Task Guide() { await ConfirmLocalized("guide", - "http://nadekobot.readthedocs.io/en/latest/Commands%20List/", - "http://nadekobot.readthedocs.io/en/latest/").ConfigureAwait(false); + "http://nadekobot.readthedocs.io/en/1.3x/Commands%20List/", + "http://nadekobot.readthedocs.io/en/1.3x/").ConfigureAwait(false); } [NadekoCommand, Usage, Description, Aliases] From b381ee00b6ca69d05cbac4193fa022e128f43f09 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Mon, 19 Jun 2017 15:42:10 +0200 Subject: [PATCH 03/26] Huge changes to make shards run in separate processes --- .../ModuleBehaviors/IEarlyBlockingExecutor.cs | 2 +- .../ModuleBehaviors/ILateBlocker.cs | 2 +- .../ModuleBehaviors/ILateExecutor.cs | 2 +- .../ShardCom/IShardComMessage.cs | 16 +++ .../DataStructures/ShardCom/ShardComClient.cs | 22 +++ .../DataStructures/ShardCom/ShardComServer.cs | 36 +++++ .../TypeReaders/GuildTypeReader.cs | 4 +- .../Commands/SelfAssignedRolesCommand.cs | 2 +- .../Administration/Commands/SelfCommands.cs | 54 +++---- .../Commands/TimeZoneCommands.cs | 2 +- .../CustomReactions/CustomReactions.cs | 4 +- .../Modules/Gambling/Commands/AnimalRacing.cs | 8 +- .../Gambling/Commands/CurrencyEvents.cs | 8 +- .../Modules/Gambling/Commands/FlowerShop.cs | 4 +- .../Modules/Games/Commands/Acropobia.cs | 8 +- .../Games/Commands/Hangman/HangmanGame.cs | 4 +- .../Modules/Games/Commands/HangmanCommands.cs | 4 +- .../Games/Commands/Models/TypingGame.cs | 4 +- .../Modules/Games/Commands/PollCommands.cs | 4 +- .../Games/Commands/SpeedTypingCommands.cs | 4 +- .../Modules/Games/Commands/TicTacToe.cs | 8 +- .../Games/Commands/Trivia/TriviaGame.cs | 4 +- .../Modules/Games/Commands/TriviaCommands.cs | 4 +- src/NadekoBot/Modules/Music/Music.cs | 4 +- src/NadekoBot/Modules/NadekoModule.cs | 7 +- .../Permissions/Commands/FilterCommands.cs | 2 +- .../Utility/Commands/CommandMapCommands.cs | 4 +- .../Modules/Utility/Commands/InfoCommands.cs | 4 +- .../Utility/Commands/RepeatCommands.cs | 4 +- src/NadekoBot/Modules/Utility/Utility.cs | 80 ++++++----- src/NadekoBot/NadekoBot.cs | 136 ++++++++++++------ src/NadekoBot/Program.cs | 11 +- src/NadekoBot/Properties/launchSettings.json | 8 ++ .../Administration/AutoAssignRoleService.cs | 4 +- .../Administration/GameVoiceChannelService.cs | 4 +- .../Administration/LogCommandService.cs | 80 +++++------ .../Services/Administration/MuteService.cs | 4 +- .../Administration/PlayingRotateService.cs | 26 ++-- .../Administration/ProtectionService.cs | 4 +- .../Administration/RatelimitService.cs | 4 +- .../Services/Administration/SelfService.cs | 24 ++-- .../Services/Administration/VcRoleService.cs | 4 +- .../Services/Administration/VplusTService.cs | 4 +- .../ClashOfClans/ClashOfClansService.cs | 4 +- src/NadekoBot/Services/CommandHandler.cs | 4 +- .../CustomReactions/CustomReactionsService.cs | 9 +- .../Services/CustomReactions/Extensions.cs | 12 +- .../Repositories/IGuildConfigRepository.cs | 2 +- .../Impl/GuildConfigRepository.cs | 6 +- .../Discord/SocketMessageEventWrapper.cs | 4 +- .../Services/Games/ChatterbotService.cs | 6 +- src/NadekoBot/Services/Games/GamesService.cs | 4 +- src/NadekoBot/Services/Games/Poll.cs | 4 +- src/NadekoBot/Services/Games/PollService.cs | 6 +- .../Services/GreetSettingsService.cs | 4 +- src/NadekoBot/Services/Help/HelpService.cs | 2 +- src/NadekoBot/Services/IBotCredentials.cs | 1 + src/NadekoBot/Services/IImagesService.cs | 2 +- src/NadekoBot/Services/Impl/ImagesService.cs | 8 +- src/NadekoBot/Services/Impl/StatsService.cs | 53 +++---- src/NadekoBot/Services/LogSetup.cs | 28 ++++ .../Services/Permissions/CmdCdService.cs | 2 +- .../Services/Permissions/FilterService.cs | 2 +- .../Permissions/GlobalPermissionService.cs | 2 +- .../Permissions/PermissionsService.cs | 5 +- .../Services/Searches/SearchesService.cs | 4 +- .../Searches/StreamNotificationService.cs | 4 +- .../Utility/MessageRepeaterService.cs | 2 +- .../Services/Utility/RemindService.cs | 4 +- .../Services/Utility/RepeatRunner.cs | 2 +- .../Services/Utility/UtilityService.cs | 4 +- src/NadekoBot/ShardsCoordinator.cs | 95 ++++++++++++ src/NadekoBot/_Extensions/Extensions.cs | 4 +- 73 files changed, 586 insertions(+), 331 deletions(-) create mode 100644 src/NadekoBot/DataStructures/ShardCom/IShardComMessage.cs create mode 100644 src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs create mode 100644 src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs create mode 100644 src/NadekoBot/Properties/launchSettings.json create mode 100644 src/NadekoBot/Services/LogSetup.cs create mode 100644 src/NadekoBot/ShardsCoordinator.cs diff --git a/src/NadekoBot/DataStructures/ModuleBehaviors/IEarlyBlockingExecutor.cs b/src/NadekoBot/DataStructures/ModuleBehaviors/IEarlyBlockingExecutor.cs index f28eaf4f..a3e004b1 100644 --- a/src/NadekoBot/DataStructures/ModuleBehaviors/IEarlyBlockingExecutor.cs +++ b/src/NadekoBot/DataStructures/ModuleBehaviors/IEarlyBlockingExecutor.cs @@ -13,6 +13,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors /// Try to execute some logic within some module's service. /// /// Whether it should block other command executions after it. - Task TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg); + Task TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg); } } diff --git a/src/NadekoBot/DataStructures/ModuleBehaviors/ILateBlocker.cs b/src/NadekoBot/DataStructures/ModuleBehaviors/ILateBlocker.cs index 3b3fc020..68f33206 100644 --- a/src/NadekoBot/DataStructures/ModuleBehaviors/ILateBlocker.cs +++ b/src/NadekoBot/DataStructures/ModuleBehaviors/ILateBlocker.cs @@ -6,7 +6,7 @@ namespace NadekoBot.DataStructures.ModuleBehaviors { public interface ILateBlocker { - Task TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, + Task TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName); } } diff --git a/src/NadekoBot/DataStructures/ModuleBehaviors/ILateExecutor.cs b/src/NadekoBot/DataStructures/ModuleBehaviors/ILateExecutor.cs index 3cf11603..a7b3e52e 100644 --- a/src/NadekoBot/DataStructures/ModuleBehaviors/ILateExecutor.cs +++ b/src/NadekoBot/DataStructures/ModuleBehaviors/ILateExecutor.cs @@ -9,6 +9,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors /// public interface ILateExecutor { - Task LateExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg); + Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg); } } diff --git a/src/NadekoBot/DataStructures/ShardCom/IShardComMessage.cs b/src/NadekoBot/DataStructures/ShardCom/IShardComMessage.cs new file mode 100644 index 00000000..9fb1f5d0 --- /dev/null +++ b/src/NadekoBot/DataStructures/ShardCom/IShardComMessage.cs @@ -0,0 +1,16 @@ +using Discord; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.DataStructures.ShardCom +{ + public class ShardComMessage + { + public int ShardId { get; set; } + public ConnectionState ConnectionState { get; set; } + public int Guilds { get; set; } + } +} diff --git a/src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs b/src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs new file mode 100644 index 00000000..a8857f3e --- /dev/null +++ b/src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs @@ -0,0 +1,22 @@ +using Newtonsoft.Json; +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.DataStructures.ShardCom +{ + public class ShardComClient + { + public async Task Send(ShardComMessage data) + { + var msg = JsonConvert.SerializeObject(data); + using (var client = new UdpClient()) + { + var bytes = Encoding.UTF8.GetBytes(msg); + await client.SendAsync(bytes, bytes.Length, IPAddress.Loopback.ToString(), ShardComServer.Port).ConfigureAwait(false); + } + } + } +} diff --git a/src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs b/src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs new file mode 100644 index 00000000..61c35a85 --- /dev/null +++ b/src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs @@ -0,0 +1,36 @@ +using Newtonsoft.Json; +using System; +using System.Net; +using System.Net.Sockets; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.DataStructures.ShardCom +{ + public class ShardComServer : IDisposable + { + public const int Port = 5664; + private readonly UdpClient _client = new UdpClient(Port); + + public void Start() + { + Task.Run(async () => + { + var ip = new IPEndPoint(IPAddress.Any, 0); + while (true) + { + var recv = await _client.ReceiveAsync(); + var data = Encoding.UTF8.GetString(recv.Buffer); + var _ = OnDataReceived(JsonConvert.DeserializeObject(data)); + } + }); + } + + public void Dispose() + { + _client.Dispose(); + } + + public event Func OnDataReceived = delegate { return Task.CompletedTask; }; + } +} diff --git a/src/NadekoBot/DataStructures/TypeReaders/GuildTypeReader.cs b/src/NadekoBot/DataStructures/TypeReaders/GuildTypeReader.cs index 63971f5a..3bb72d4c 100644 --- a/src/NadekoBot/DataStructures/TypeReaders/GuildTypeReader.cs +++ b/src/NadekoBot/DataStructures/TypeReaders/GuildTypeReader.cs @@ -7,9 +7,9 @@ namespace NadekoBot.TypeReaders { public class GuildTypeReader : TypeReader { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; - public GuildTypeReader(DiscordShardedClient client) + public GuildTypeReader(DiscordSocketClient client) { _client = client; } diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs index 9815fa1b..3ad63210 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfAssignedRolesCommand.cs @@ -140,7 +140,7 @@ namespace NadekoBot.Modules.Administration await uow.CompleteAsync(); } - await Context.Channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client, page, (curPage) => + await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page, (curPage) => { return new EmbedBuilder() .WithTitle(GetText("self_assign_list", roleCnt)) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index aa99eeab..5e5ecb33 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -13,6 +13,7 @@ using NadekoBot.Services; using NadekoBot.Services.Database.Models; using Microsoft.EntityFrameworkCore; using NadekoBot.Services.Administration; +using System.Diagnostics; namespace NadekoBot.Modules.Administration { @@ -25,10 +26,10 @@ namespace NadekoBot.Modules.Administration private static readonly object _locker = new object(); private readonly SelfService _service; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly IImagesService _images; - public SelfCommands(DbService db, SelfService service, DiscordShardedClient client, + public SelfCommands(DbService db, SelfService service, DiscordSocketClient client, IImagesService images) { _db = db; @@ -204,28 +205,29 @@ namespace NadekoBot.Modules.Administration } - [NadekoCommand, Usage, Description, Aliases] - [OwnerOnly] - public async Task ConnectShard(int shardid) - { - var shard = _client.GetShard(shardid); + //todo 2 shard commands + //[NadekoCommand, Usage, Description, Aliases] + //[OwnerOnly] + //public async Task ConnectShard(int shardid) + //{ + // var shard = _client.GetShard(shardid); - if (shard == null) - { - await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false); - return; - } - try - { - await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false); - await shard.StartAsync().ConfigureAwait(false); - await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false); - } - catch (Exception ex) - { - _log.Warn(ex); - } - } + // if (shard == null) + // { + // await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false); + // return; + // } + // try + // { + // await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false); + // await shard.StartAsync().ConfigureAwait(false); + // await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false); + // } + // catch (Exception ex) + // { + // _log.Warn(ex); + // } + //} [NadekoCommand, Usage, Description, Aliases] [OwnerOnly] @@ -417,8 +419,10 @@ namespace NadekoBot.Modules.Administration [OwnerOnly] public async Task ReloadImages() { - var time = _images.Reload(); - await ReplyConfirmLocalized("images_loaded", time.TotalSeconds.ToString("F3")).ConfigureAwait(false); + var sw = Stopwatch.StartNew(); + _images.Reload(); + sw.Stop(); + await ReplyConfirmLocalized("images_loaded", sw.Elapsed.TotalSeconds.ToString("F3")).ConfigureAwait(false); } private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) diff --git a/src/NadekoBot/Modules/Administration/Commands/TimeZoneCommands.cs b/src/NadekoBot/Modules/Administration/Commands/TimeZoneCommands.cs index e054288c..c97fdbca 100644 --- a/src/NadekoBot/Modules/Administration/Commands/TimeZoneCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/TimeZoneCommands.cs @@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Administration .ToArray(); var timezonesPerPage = 20; - await Context.Channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client, page, + await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page, (curPage) => new EmbedBuilder() .WithOkColor() .WithTitle(GetText("timezones_available")) diff --git a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs index 5dac3b9c..ae033cad 100644 --- a/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs +++ b/src/NadekoBot/Modules/CustomReactions/CustomReactions.cs @@ -17,10 +17,10 @@ namespace NadekoBot.Modules.CustomReactions private readonly IBotCredentials _creds; private readonly DbService _db; private readonly CustomReactionsService _crs; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; public CustomReactions(IBotCredentials creds, DbService db, CustomReactionsService crs, - DiscordShardedClient client) + DiscordSocketClient client) { _creds = creds; _db = db; diff --git a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs index 4db985e5..46cd25b3 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/AnimalRacing.cs @@ -22,12 +22,12 @@ namespace NadekoBot.Modules.Gambling { private readonly BotConfig _bc; private readonly CurrencyService _cs; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; public static ConcurrentDictionary AnimalRaces { get; } = new ConcurrentDictionary(); - public AnimalRacing(BotConfig bc, CurrencyService cs, DiscordShardedClient client) + public AnimalRacing(BotConfig bc, CurrencyService cs, DiscordSocketClient client) { _bc = bc; _cs = cs; @@ -82,14 +82,14 @@ namespace NadekoBot.Modules.Gambling private readonly ITextChannel _raceChannel; private readonly BotConfig _bc; private readonly CurrencyService _cs; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly ILocalization _localization; private readonly NadekoStrings _strings; public bool Started { get; private set; } public AnimalRace(ulong serverId, ITextChannel channel, string prefix, BotConfig bc, - CurrencyService cs, DiscordShardedClient client, ILocalization localization, + CurrencyService cs, DiscordSocketClient client, ILocalization localization, NadekoStrings strings) { _prefix = prefix; diff --git a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs index 76369c15..644823bc 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/CurrencyEvents.cs @@ -34,11 +34,11 @@ namespace NadekoBot.Modules.Gambling .ToArray(); private string _secretCode = string.Empty; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly BotConfig _bc; private readonly CurrencyService _cs; - public CurrencyEvents(DiscordShardedClient client, BotConfig bc, CurrencyService cs) + public CurrencyEvents(DiscordSocketClient client, BotConfig bc, CurrencyService cs) { _client = client; _bc = bc; @@ -151,7 +151,7 @@ namespace NadekoBot.Modules.Gambling { private readonly ConcurrentHashSet _flowerReactionAwardedUsers = new ConcurrentHashSet(); private readonly Logger _log; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly CurrencyService _cs; private IUserMessage StartingMessage { get; set; } @@ -159,7 +159,7 @@ namespace NadekoBot.Modules.Gambling private CancellationTokenSource Source { get; } private CancellationToken CancelToken { get; } - public FlowerReactionEvent(DiscordShardedClient client, CurrencyService cs) + public FlowerReactionEvent(DiscordSocketClient client, CurrencyService cs) { _log = LogManager.GetCurrentClassLogger(); _client = client; diff --git a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs index dfc8d648..dd4fd309 100644 --- a/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs +++ b/src/NadekoBot/Modules/Gambling/Commands/FlowerShop.cs @@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Gambling private readonly BotConfig _bc; private readonly DbService _db; private readonly CurrencyService _cs; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; public enum Role { @@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Gambling List } - public FlowerShop(BotConfig bc, DbService db, CurrencyService cs, DiscordShardedClient client) + public FlowerShop(BotConfig bc, DbService db, CurrencyService cs, DiscordSocketClient client) { _db = db; _bc = bc; diff --git a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs index 0d8e337f..44b64808 100644 --- a/src/NadekoBot/Modules/Games/Commands/Acropobia.cs +++ b/src/NadekoBot/Modules/Games/Commands/Acropobia.cs @@ -20,12 +20,12 @@ namespace NadekoBot.Modules.Games [Group] public class Acropobia : NadekoSubmodule { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; //channelId, game public static ConcurrentDictionary AcrophobiaGames { get; } = new ConcurrentDictionary(); - public Acropobia(DiscordShardedClient client) + public Acropobia(DiscordSocketClient client) { _client = client; } @@ -86,10 +86,10 @@ namespace NadekoBot.Modules.Games //text, votes private readonly ConcurrentDictionary _votes = new ConcurrentDictionary(); private readonly Logger _log; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly NadekoStrings _strings; - public AcrophobiaGame(DiscordShardedClient client, NadekoStrings strings, ITextChannel channel, int time) + public AcrophobiaGame(DiscordSocketClient client, NadekoStrings strings, ITextChannel channel, int time) { _log = LogManager.GetCurrentClassLogger(); _client = client; diff --git a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs index 24ca87c9..eddd00fc 100644 --- a/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Hangman/HangmanGame.cs @@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Games.Hangman public class HangmanGame: IDisposable { private readonly Logger _log; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; public IMessageChannel GameChannel { get; } public HashSet Guesses { get; } = new HashSet(); @@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Games.Hangman public event Action OnEnded; - public HangmanGame(DiscordShardedClient client, IMessageChannel channel, string type) + public HangmanGame(DiscordSocketClient client, IMessageChannel channel, string type) { _log = LogManager.GetCurrentClassLogger(); _client = client; diff --git a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs index 633be81f..c515c0b8 100644 --- a/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/HangmanCommands.cs @@ -15,9 +15,9 @@ namespace NadekoBot.Modules.Games [Group] public class HangmanCommands : NadekoSubmodule { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; - public HangmanCommands(DiscordShardedClient client) + public HangmanCommands(DiscordSocketClient client) { _client = client; } diff --git a/src/NadekoBot/Modules/Games/Commands/Models/TypingGame.cs b/src/NadekoBot/Modules/Games/Commands/Models/TypingGame.cs index db670fd2..92b01eb3 100644 --- a/src/NadekoBot/Modules/Games/Commands/Models/TypingGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Models/TypingGame.cs @@ -20,13 +20,13 @@ namespace NadekoBot.Modules.Games.Models public bool IsActive { get; private set; } private readonly Stopwatch sw; private readonly List finishedUserIds; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly GamesService _games; private readonly string _prefix; private Logger _log { get; } - public TypingGame(GamesService games, DiscordShardedClient client, ITextChannel channel, string prefix) //kek@prefix + public TypingGame(GamesService games, DiscordSocketClient client, ITextChannel channel, string prefix) //kek@prefix { _log = LogManager.GetCurrentClassLogger(); _games = games; diff --git a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs index 487473f0..1cf5b951 100644 --- a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs @@ -13,10 +13,10 @@ namespace NadekoBot.Modules.Games [Group] public class PollCommands : NadekoSubmodule { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly PollService _polls; - public PollCommands(DiscordShardedClient client, PollService polls) + public PollCommands(DiscordSocketClient client, PollService polls) { _client = client; _polls = polls; diff --git a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs index 72663094..6cce5191 100644 --- a/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/SpeedTypingCommands.cs @@ -20,9 +20,9 @@ namespace NadekoBot.Modules.Games { public static ConcurrentDictionary RunningContests = new ConcurrentDictionary(); private readonly GamesService _games; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; - public SpeedTypingCommands(DiscordShardedClient client, GamesService games) + public SpeedTypingCommands(DiscordSocketClient client, GamesService games) { _games = games; _client = client; diff --git a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs index 7de40565..6f626325 100644 --- a/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs +++ b/src/NadekoBot/Modules/Games/Commands/TicTacToe.cs @@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Games private static readonly Dictionary _games = new Dictionary(); private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1); - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; - public TicTacToeCommands(DiscordShardedClient client) + public TicTacToeCommands(DiscordSocketClient client) { _client = client; } @@ -87,9 +87,9 @@ namespace NadekoBot.Modules.Games private IUserMessage _previousMessage; private Timer _timeoutTimer; private readonly NadekoStrings _strings; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; - public TicTacToe(NadekoStrings strings, DiscordShardedClient client, ITextChannel channel, IGuildUser firstUser) + public TicTacToe(NadekoStrings strings, DiscordSocketClient client, ITextChannel channel, IGuildUser firstUser) { _channel = channel; _strings = strings; diff --git a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs index ea6e1e2c..b1b7d477 100644 --- a/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs +++ b/src/NadekoBot/Modules/Games/Commands/Trivia/TriviaGame.cs @@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Games.Trivia private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1); private readonly Logger _log; private readonly NadekoStrings _strings; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly BotConfig _bc; private readonly CurrencyService _cs; @@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Games.Trivia public int WinRequirement { get; } - public TriviaGame(NadekoStrings strings, DiscordShardedClient client, BotConfig bc, + public TriviaGame(NadekoStrings strings, DiscordSocketClient client, BotConfig bc, CurrencyService cs, IGuild guild, ITextChannel channel, bool showHints, int winReq, bool isPokemon) { diff --git a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs index d38e04dd..ac9cdcc3 100644 --- a/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/TriviaCommands.cs @@ -18,12 +18,12 @@ namespace NadekoBot.Modules.Games public class TriviaCommands : NadekoSubmodule { private readonly CurrencyService _cs; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly BotConfig _bc; public static ConcurrentDictionary RunningTrivias { get; } = new ConcurrentDictionary(); - public TriviaCommands(DiscordShardedClient client, BotConfig bc, CurrencyService cs) + public TriviaCommands(DiscordSocketClient client, BotConfig bc, CurrencyService cs) { _cs = cs; _client = client; diff --git a/src/NadekoBot/Modules/Music/Music.cs b/src/NadekoBot/Modules/Music/Music.cs index afd60bb2..ebec33c5 100644 --- a/src/NadekoBot/Modules/Music/Music.cs +++ b/src/NadekoBot/Modules/Music/Music.cs @@ -22,12 +22,12 @@ namespace NadekoBot.Modules.Music public class Music : NadekoTopLevelModule { private static MusicService _music; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly IBotCredentials _creds; private readonly IGoogleApiService _google; private readonly DbService _db; - public Music(DiscordShardedClient client, IBotCredentials creds, IGoogleApiService google, + public Music(DiscordSocketClient client, IBotCredentials creds, IGoogleApiService google, DbService db, MusicService music) { _client = client; diff --git a/src/NadekoBot/Modules/NadekoModule.cs b/src/NadekoBot/Modules/NadekoModule.cs index dae471d4..45abaea9 100644 --- a/src/NadekoBot/Modules/NadekoModule.cs +++ b/src/NadekoBot/Modules/NadekoModule.cs @@ -86,13 +86,12 @@ namespace NadekoBot.Modules var text = GetText(textKey, replacements); return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + text); } - - // todo maybe make this generic and use - // TypeConverter typeConverter = TypeDescriptor.GetConverter(propType); + + // TypeConverter typeConverter = TypeDescriptor.GetConverter(propType); ? public async Task GetUserInputAsync(ulong userId, ulong channelId) { var userInputTask = new TaskCompletionSource(); - var dsc = (DiscordShardedClient)Context.Client; + var dsc = (DiscordSocketClient)Context.Client; try { dsc.MessageReceived += MessageReceived; diff --git a/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs b/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs index 371678ff..1329fc0b 100644 --- a/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs +++ b/src/NadekoBot/Modules/Permissions/Commands/FilterCommands.cs @@ -195,7 +195,7 @@ namespace NadekoBot.Modules.Permissions var fws = fwHash.ToArray(); - await channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client, + await channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page, (curPage) => new EmbedBuilder() diff --git a/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs b/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs index d38cfb90..03316135 100644 --- a/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/CommandMapCommands.cs @@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Utility { private readonly CommandMapService _service; private readonly DbService _db; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; - public CommandMapCommands(CommandMapService service, DbService db, DiscordShardedClient client) + public CommandMapCommands(CommandMapService service, DbService db, DiscordSocketClient client) { _service = service; _db = db; diff --git a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs index 3a5b8fe8..e3c625c4 100644 --- a/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/InfoCommands.cs @@ -16,10 +16,10 @@ namespace NadekoBot.Modules.Utility [Group] public class InfoCommands : NadekoSubmodule { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly IStatsService _stats; - public InfoCommands(DiscordShardedClient client, IStatsService stats, CommandHandler ch) + public InfoCommands(DiscordSocketClient client, IStatsService stats, CommandHandler ch) { _client = client; _stats = stats; diff --git a/src/NadekoBot/Modules/Utility/Commands/RepeatCommands.cs b/src/NadekoBot/Modules/Utility/Commands/RepeatCommands.cs index 6561712d..89619c1c 100644 --- a/src/NadekoBot/Modules/Utility/Commands/RepeatCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/RepeatCommands.cs @@ -22,10 +22,10 @@ namespace NadekoBot.Modules.Utility public class RepeatCommands : NadekoSubmodule { private readonly MessageRepeaterService _service; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly DbService _db; - public RepeatCommands(MessageRepeaterService service, DiscordShardedClient client, DbService db) + public RepeatCommands(MessageRepeaterService service, DiscordSocketClient client, DbService db) { _service = service; _client = client; diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 4774a266..4fecdf5e 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -24,15 +24,17 @@ namespace NadekoBot.Modules.Utility public partial class Utility : NadekoTopLevelModule { private static ConcurrentDictionary _rotatingRoleColors = new ConcurrentDictionary(); - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly IStatsService _stats; private readonly IBotCredentials _creds; + private readonly NadekoBot _bot; - public Utility(DiscordShardedClient client, IStatsService stats, IBotCredentials creds) + public Utility(NadekoBot bot, DiscordSocketClient client, IStatsService stats, IBotCredentials creds) { _client = client; _stats = stats; _creds = creds; + _bot = bot; } //[NadekoCommand, Usage, Description, Aliases] @@ -352,56 +354,56 @@ namespace NadekoBot.Modules.Utility await Context.Channel.SendConfirmAsync($"{Context.User.Mention} https://discord.gg/{invite.Code}"); } + //todo 2 shard commands + //[NadekoCommand, Usage, Description, Aliases] + //public async Task ShardStats(int page = 1) + //{ + // if (--page < 0) + // return; - [NadekoCommand, Usage, Description, Aliases] - public async Task ShardStats(int page = 1) - { - if (--page < 0) - return; + // var status = string.Join(", ", _client.Shards.GroupBy(x => x.ConnectionState) + // .Select(x => $"{x.Count()} {x.Key}") + // .ToArray()); - var status = string.Join(", ", _client.Shards.GroupBy(x => x.ConnectionState) - .Select(x => $"{x.Count()} {x.Key}") - .ToArray()); - - var allShardStrings = _client.Shards - .Select(x => - GetText("shard_stats_txt", x.ShardId.ToString(), - Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString()))) - .ToArray(); + // var allShardStrings = _client.Shards + // .Select(x => + // GetText("shard_stats_txt", x.ShardId.ToString(), + // Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString()))) + // .ToArray(); - await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) => - { + // await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) => + // { - var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25)); + // var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25)); - if (string.IsNullOrWhiteSpace(str)) - str = GetText("no_shards_on_page"); + // if (string.IsNullOrWhiteSpace(str)) + // str = GetText("no_shards_on_page"); - return new EmbedBuilder() - .WithAuthor(a => a.WithName(GetText("shard_stats"))) - .WithTitle(status) - .WithOkColor() - .WithDescription(str); - }, allShardStrings.Length / 25); - } + // return new EmbedBuilder() + // .WithAuthor(a => a.WithName(GetText("shard_stats"))) + // .WithTitle(status) + // .WithOkColor() + // .WithDescription(str); + // }, allShardStrings.Length / 25); + //} - [NadekoCommand, Usage, Description, Aliases] - public async Task ShardId(IGuild guild) - { - var shardId = _client.GetShardIdFor(guild); + //[NadekoCommand, Usage, Description, Aliases] + //public async Task ShardId(IGuild guild) + //{ + // var shardId = _client.GetShardIdFor(guild); - await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false); - } + // await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false); + //} [NadekoCommand, Usage, Description, Aliases] public async Task Stats() { - var shardId = Context.Guild != null - ? _client.GetShardIdFor(Context.Guild) - : 0; - + //var shardId = Context.Guild != null + // ? _client.GetShardIdFor(Context.Guild) + // : 0; + await Context.Channel.EmbedAsync( new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}") @@ -409,7 +411,7 @@ namespace NadekoBot.Modules.Utility .WithIconUrl("https://cdn.discordapp.com/avatars/116275390695079945/b21045e778ef21c96d175400e779f0fb.jpg")) .AddField(efb => efb.WithName(GetText("author")).WithValue(_stats.Author).WithIsInline(true)) .AddField(efb => efb.WithName(GetText("botid")).WithValue(_client.CurrentUser.Id.ToString()).WithIsInline(true)) - .AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{shardId} / {_client.Shards.Count}").WithIsInline(true)) + .AddField(efb => efb.WithName(GetText("shard")).WithValue($"#{_bot.ShardId} / {_creds.TotalShards}").WithIsInline(true)) .AddField(efb => efb.WithName(GetText("commands_ran")).WithValue(_stats.CommandsRan.ToString()).WithIsInline(true)) .AddField(efb => efb.WithName(GetText("messages")).WithValue($"{_stats.MessageCounter} ({_stats.MessagesPerSecond:F2}/sec)").WithIsInline(true)) .AddField(efb => efb.WithName(GetText("memory")).WithValue($"{_stats.Heap} MB").WithIsInline(true)) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 44802af6..1c086a7e 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -27,8 +27,7 @@ using NadekoBot.Services.Utility; using NadekoBot.Services.Help; using System.IO; using NadekoBot.Services.Pokemon; -using NadekoBot.DataStructures; -using NadekoBot.Extensions; +using NadekoBot.DataStructures.ShardCom; namespace NadekoBot { @@ -45,47 +44,74 @@ namespace NadekoBot public static Color OkColor { get; private set; } public static Color ErrorColor { get; private set; } - public ImmutableArray AllGuildConfigs { get; } + public ImmutableArray AllGuildConfigs { get; private set; } public BotConfig BotConfig { get; } public DbService Db { get; } public CommandService CommandService { get; } public CommandHandler CommandHandler { get; private set; } - public Localization Localization { get; } - public NadekoStrings Strings { get; } - public StatsService Stats { get; } + public Localization Localization { get; private set; } + public NadekoStrings Strings { get; private set; } + public StatsService Stats { get; private set; } public ImagesService Images { get; } public CurrencyService Currency { get; } public GoogleApiService GoogleApi { get; } - public DiscordShardedClient Client { get; } + public DiscordSocketClient Client { get; } public bool Ready { get; private set; } public INServiceProvider Services { get; private set; } public BotCredentials Credentials { get; } - public NadekoBot() + private const string _mutexName = @"Global\nadeko_shards_lock"; + private readonly Semaphore sem = new Semaphore(1, 1, _mutexName); + public int ShardId { get; } + private readonly Thread waitForParentKill; + private readonly ShardComClient _comClient = new ShardComClient(); + + public NadekoBot(int shardId, int parentProcessId) { - SetupLogger(); + if (shardId < 0) + throw new ArgumentOutOfRangeException(nameof(shardId)); + + ShardId = shardId; + + LogSetup.SetupLogger(); _log = LogManager.GetCurrentClassLogger(); TerribleElevatedPermissionCheck(); - + + waitForParentKill = new Thread(new ThreadStart(() => + { + try + { + var p = Process.GetProcessById(parentProcessId); + if (p == null) + return; + p.WaitForExit(); + } + finally + { + Environment.Exit(10); + } + })); + waitForParentKill.Start(); + Credentials = new BotCredentials(); Db = new DbService(Credentials); using (var uow = Db.UnitOfWork) { - AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs().ToImmutableArray(); BotConfig = uow.BotConfig.GetOrCreate(); OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16)); ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16)); } - Client = new DiscordShardedClient(new DiscordSocketConfig + Client = new DiscordSocketClient(new DiscordSocketConfig { MessageCacheSize = 10, LogLevel = LogSeverity.Warning, - TotalShards = Credentials.TotalShards, ConnectionTimeout = int.MaxValue, + TotalShards = Credentials.TotalShards, + ShardId = shardId, AlwaysDownloadUsers = false, }); @@ -96,21 +122,45 @@ namespace NadekoBot }); //foundation services - Localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db); - Strings = new NadekoStrings(Localization); - CommandHandler = new CommandHandler(Client, Db, BotConfig, AllGuildConfigs, CommandService, Credentials, this); - Stats = new StatsService(Client, CommandHandler, Credentials); Images = new ImagesService(); Currency = new CurrencyService(BotConfig, Db); GoogleApi = new GoogleApiService(Credentials); + StartSendingData(); + #if GLOBAL_NADEKO Client.Log += Client_Log; #endif } + private void StartSendingData() + { + Task.Run(async () => + { + while (true) + { + await _comClient.Send(new ShardComMessage() + { + ConnectionState = Client.ConnectionState, + Guilds = Client.ConnectionState == ConnectionState.Connected ? Client.Guilds.Count : 0, + ShardId = Client.ShardId, + }); + await Task.Delay(1000); + } + }); + } + private void AddServices() { + using (var uow = Db.UnitOfWork) + { + AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(Client.Guilds.Select(x => (long)x.Id).ToList()).ToImmutableArray(); + } + Localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db); + Strings = new NadekoStrings(Localization); + CommandHandler = new CommandHandler(Client, Db, BotConfig, AllGuildConfigs, CommandService, Credentials, this); + Stats = new StatsService(Client, CommandHandler, Credentials); + var soundcloudApiService = new SoundCloudApiService(Credentials); #region help @@ -185,7 +235,7 @@ namespace NadekoBot .Add(Credentials) .Add(CommandService) .Add(Strings) - .Add(Client) + .Add(Client) .Add(BotConfig) .Add(Currency) .Add(CommandHandler) @@ -242,19 +292,30 @@ namespace NadekoBot CommandService.AddTypeReader(new GuildDateTimeTypeReader(guildTimezoneService)); } - private async Task LoginAsync(string token) + private Task LoginAsync(string token) { - _log.Info("Logging in..."); //connect - await Client.LoginAsync(TokenType.Bot, token).ConfigureAwait(false); - await Client.StartAsync().ConfigureAwait(false); - - _log.Info("Waiting for all shards to connect..."); - while (!Client.Shards.All(x => x.ConnectionState == ConnectionState.Connected)) + try { sem.WaitOne(); } catch (AbandonedMutexException) { } + _log.Info("Shard {0} logging in ...", ShardId); + try { - _log.Info("Connecting... {0}/{1}", Client.Shards.Count(x => x.ConnectionState == ConnectionState.Connected), Client.Shards.Count); - await Task.Delay(1000).ConfigureAwait(false); + Client.LoginAsync(TokenType.Bot, token).GetAwaiter().GetResult(); + Client.StartAsync().GetAwaiter().GetResult(); + while (Client.ConnectionState != ConnectionState.Connected) + Task.Delay(100).GetAwaiter().GetResult(); } + finally + { + _log.Info("Shard {0} logged in ...", ShardId); + sem.Release(); + } + return Task.CompletedTask; + //_log.Info("Waiting for all shards to connect..."); + //while (!Client.Shards.All(x => x.ConnectionState == ConnectionState.Connected)) + //{ + // _log.Info("Connecting... {0}/{1}", Client.Shards.Count(x => x.ConnectionState == ConnectionState.Connected), Client.Shards.Count); + // await Task.Delay(1000).ConfigureAwait(false); + //} } public async Task RunAsync(params string[] args) @@ -265,11 +326,11 @@ namespace NadekoBot await LoginAsync(Credentials.Token).ConfigureAwait(false); - _log.Info("Loading services..."); + _log.Info($"Shard {ShardId} loading services..."); AddServices(); sw.Stop(); - _log.Info($"Connected in {sw.Elapsed.TotalSeconds:F2} s"); + _log.Info($"Shard {ShardId} connected in {sw.Elapsed.TotalSeconds:F2} s"); var stats = Services.GetService(); stats.Initialize(); @@ -298,7 +359,8 @@ namespace NadekoBot .ForEach(x => CommandService.RemoveModuleAsync(x)); #endif Ready = true; - _log.Info(await stats.Print().ConfigureAwait(false)); + _log.Info($"Shard {ShardId} ready."); + //_log.Info(await stats.Print().ConfigureAwait(false)); } private Task Client_Log(LogMessage arg) @@ -330,19 +392,5 @@ namespace NadekoBot Environment.Exit(2); } } - - private static void SetupLogger() - { - var logConfig = new LoggingConfiguration(); - var consoleTarget = new ColoredConsoleTarget() - { - Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}" - }; - logConfig.AddTarget("Console", consoleTarget); - - logConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget)); - - LogManager.Configuration = logConfig; - } } } diff --git a/src/NadekoBot/Program.cs b/src/NadekoBot/Program.cs index 0c8832e2..20f3a052 100644 --- a/src/NadekoBot/Program.cs +++ b/src/NadekoBot/Program.cs @@ -2,7 +2,14 @@ { public class Program { - public static void Main(string[] args) => - new NadekoBot().RunAndBlockAsync(args).GetAwaiter().GetResult(); + public static void Main(string[] args) + { + if (args.Length == 0) + return; + if (args[0].ToLowerInvariant() == "main") + new ShardsCoordinator().RunAndBlockAsync(args).GetAwaiter().GetResult(); + else if (int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId)) + new NadekoBot(shardId, parentProcessId).RunAndBlockAsync(args).GetAwaiter().GetResult(); + } } } diff --git a/src/NadekoBot/Properties/launchSettings.json b/src/NadekoBot/Properties/launchSettings.json new file mode 100644 index 00000000..77336a17 --- /dev/null +++ b/src/NadekoBot/Properties/launchSettings.json @@ -0,0 +1,8 @@ +{ + "profiles": { + "NadekoBot": { + "commandName": "Project", + "commandLineArgs": "main" + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/Services/Administration/AutoAssignRoleService.cs b/src/NadekoBot/Services/Administration/AutoAssignRoleService.cs index 14679b6d..7c8b8711 100644 --- a/src/NadekoBot/Services/Administration/AutoAssignRoleService.cs +++ b/src/NadekoBot/Services/Administration/AutoAssignRoleService.cs @@ -12,12 +12,12 @@ namespace NadekoBot.Services.Administration public class AutoAssignRoleService { private readonly Logger _log; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; //guildid/roleid public ConcurrentDictionary AutoAssignedRoles { get; } - public AutoAssignRoleService(DiscordShardedClient client, IEnumerable gcs) + public AutoAssignRoleService(DiscordSocketClient client, IEnumerable gcs) { _log = LogManager.GetCurrentClassLogger(); _client = client; diff --git a/src/NadekoBot/Services/Administration/GameVoiceChannelService.cs b/src/NadekoBot/Services/Administration/GameVoiceChannelService.cs index 14f9c6c6..52ea08f7 100644 --- a/src/NadekoBot/Services/Administration/GameVoiceChannelService.cs +++ b/src/NadekoBot/Services/Administration/GameVoiceChannelService.cs @@ -16,9 +16,9 @@ namespace NadekoBot.Services.Administration private readonly Logger _log; private readonly DbService _db; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; - public GameVoiceChannelService(DiscordShardedClient client, DbService db, IEnumerable gcs) + public GameVoiceChannelService(DiscordSocketClient client, DbService db, IEnumerable gcs) { _log = LogManager.GetCurrentClassLogger(); _db = db; diff --git a/src/NadekoBot/Services/Administration/LogCommandService.cs b/src/NadekoBot/Services/Administration/LogCommandService.cs index 84555345..420ada80 100644 --- a/src/NadekoBot/Services/Administration/LogCommandService.cs +++ b/src/NadekoBot/Services/Administration/LogCommandService.cs @@ -16,7 +16,7 @@ namespace NadekoBot.Services.Administration public class LogCommandService { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly Logger _log; private string PrettyCurrentTime => $"【{DateTime.UtcNow:HH:mm:ss}】"; @@ -31,7 +31,7 @@ namespace NadekoBot.Services.Administration private readonly MuteService _mute; private readonly ProtectionService _prot; - public LogCommandService(DiscordShardedClient client, NadekoStrings strings, + public LogCommandService(DiscordSocketClient client, NadekoStrings strings, IEnumerable gcs, DbService db, MuteService mute, ProtectionService prot) { _client = client; @@ -74,7 +74,7 @@ namespace NadekoBot.Services.Administration _client.UserUnbanned += _client_UserUnbanned; _client.UserJoined += _client_UserJoined; _client.UserLeft += _client_UserLeft; - _client.UserPresenceUpdated += _client_UserPresenceUpdated; + //_client.UserPresenceUpdated += _client_UserPresenceUpdated; _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated; _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS; _client.GuildMemberUpdated += _client_GuildUserUpdated; @@ -576,48 +576,48 @@ namespace NadekoBot.Services.Administration return Task.CompletedTask; } - private Task _client_UserPresenceUpdated(Optional optGuild, SocketUser usr, SocketPresence before, SocketPresence after) - { - var _ = Task.Run(async () => - { - try - { - var guild = optGuild.GetValueOrDefault() ?? (usr as SocketGuildUser)?.Guild; + //private Task _client_UserPresenceUpdated(Optional optGuild, SocketUser usr, SocketPresence before, SocketPresence after) + //{ + // var _ = Task.Run(async () => + // { + // try + // { + // var guild = optGuild.GetValueOrDefault() ?? (usr as SocketGuildUser)?.Guild; - if (guild == null) - return; + // if (guild == null) + // return; - if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting) - || (logSetting.LogUserPresenceId == null) - || before.Status == after.Status) - return; + // if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting) + // || (logSetting.LogUserPresenceId == null) + // || before.Status == after.Status) + // return; - ITextChannel logChannel; - if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserPresence)) == null) - return; - string str = ""; - if (before.Status != after.Status) - str = "🎭" + Format.Code(PrettyCurrentTime) + - GetText(logChannel.Guild, "user_status_change", - "👤" + Format.Bold(usr.Username), - Format.Bold(after.Status.ToString())); + // ITextChannel logChannel; + // if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserPresence)) == null) + // return; + // string str = ""; + // if (before.Status != after.Status) + // str = "🎭" + Format.Code(PrettyCurrentTime) + + // GetText(logChannel.Guild, "user_status_change", + // "👤" + Format.Bold(usr.Username), + // Format.Bold(after.Status.ToString())); - //if (before.Game?.Name != after.Game?.Name) - //{ - // if (str != "") - // str += "\n"; - // str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**."; - //} + // //if (before.Game?.Name != after.Game?.Name) + // //{ + // // if (str != "") + // // str += "\n"; + // // str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**."; + // //} - PresenceUpdates.AddOrUpdate(logChannel, new List() { str }, (id, list) => { list.Add(str); return list; }); - } - catch - { - // ignored - } - }); - return Task.CompletedTask; - } + // PresenceUpdates.AddOrUpdate(logChannel, new List() { str }, (id, list) => { list.Add(str); return list; }); + // } + // catch + // { + // // ignored + // } + // }); + // return Task.CompletedTask; + //} private Task _client_UserLeft(IGuildUser usr) { diff --git a/src/NadekoBot/Services/Administration/MuteService.cs b/src/NadekoBot/Services/Administration/MuteService.cs index 7ed9062a..87bde743 100644 --- a/src/NadekoBot/Services/Administration/MuteService.cs +++ b/src/NadekoBot/Services/Administration/MuteService.cs @@ -33,10 +33,10 @@ namespace NadekoBot.Services.Administration private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny); private readonly Logger _log = LogManager.GetCurrentClassLogger(); - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly DbService _db; - public MuteService(DiscordShardedClient client, IEnumerable gcs, DbService db) + public MuteService(DiscordSocketClient client, IEnumerable gcs, DbService db) { _client = client; _db = db; diff --git a/src/NadekoBot/Services/Administration/PlayingRotateService.cs b/src/NadekoBot/Services/Administration/PlayingRotateService.cs index 7662b7ca..c7a1bf41 100644 --- a/src/NadekoBot/Services/Administration/PlayingRotateService.cs +++ b/src/NadekoBot/Services/Administration/PlayingRotateService.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Services.Administration public List RotatingStatusMessages { get; } public volatile bool RotatingStatuses; private readonly Timer _t; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly BotConfig _bc; private readonly MusicService _music; private readonly Logger _log; @@ -27,7 +27,7 @@ namespace NadekoBot.Services.Administration public int Index { get; set; } } - public PlayingRotateService(DiscordShardedClient client, BotConfig bc, MusicService music) + public PlayingRotateService(DiscordSocketClient client, BotConfig bc, MusicService music) { _client = client; _bc = bc; @@ -36,7 +36,7 @@ namespace NadekoBot.Services.Administration RotatingStatusMessages = _bc.RotatingStatusMessages; RotatingStatuses = _bc.RotatingStatuses; - + _t = new Timer(async (objState) => { try @@ -52,17 +52,12 @@ namespace NadekoBot.Services.Administration var status = RotatingStatusMessages[state.Index++].Status; if (string.IsNullOrWhiteSpace(status)) return; - PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(_client,_music))); - var shards = _client.Shards; - for (int i = 0; i < shards.Count; i++) + PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(_client, _music))); + ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(client))); + try { await client.SetGameAsync(status).ConfigureAwait(false); } + catch (Exception ex) { - var curShard = shards.ElementAt(i); - ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(curShard))); - try { await shards.ElementAt(i).SetGameAsync(status).ConfigureAwait(false); } - catch (Exception ex) - { - _log.Warn(ex); - } + _log.Warn(ex); } } catch (Exception ex) @@ -72,8 +67,8 @@ namespace NadekoBot.Services.Administration }, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); } - public Dictionary> PlayingPlaceholders { get; } = - new Dictionary> { + public Dictionary> PlayingPlaceholders { get; } = + new Dictionary> { { "%servers%", (c, ms) => c.Guilds.Count.ToString()}, { "%users%", (c, ms) => c.Guilds.Sum(s => s.Users.Count).ToString()}, { "%playing%", (c, ms) => { @@ -90,7 +85,6 @@ namespace NadekoBot.Services.Administration }, { "%queued%", (c, ms) => ms.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()}, { "%time%", (c, ms) => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) }, - { "%shardcount%", (c, ms) => c.Shards.Count.ToString() }, }; public Dictionary> ShardSpecificPlaceholders { get; } = diff --git a/src/NadekoBot/Services/Administration/ProtectionService.cs b/src/NadekoBot/Services/Administration/ProtectionService.cs index 23bca7ad..6a2ae99b 100644 --- a/src/NadekoBot/Services/Administration/ProtectionService.cs +++ b/src/NadekoBot/Services/Administration/ProtectionService.cs @@ -21,10 +21,10 @@ namespace NadekoBot.Services.Administration public event Func OnAntiProtectionTriggered = delegate { return Task.CompletedTask; }; private readonly Logger _log; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly MuteService _mute; - public ProtectionService(DiscordShardedClient client, IEnumerable gcs, MuteService mute) + public ProtectionService(DiscordSocketClient client, IEnumerable gcs, MuteService mute) { _log = LogManager.GetCurrentClassLogger(); _client = client; diff --git a/src/NadekoBot/Services/Administration/RatelimitService.cs b/src/NadekoBot/Services/Administration/RatelimitService.cs index b344930f..a0f4171f 100644 --- a/src/NadekoBot/Services/Administration/RatelimitService.cs +++ b/src/NadekoBot/Services/Administration/RatelimitService.cs @@ -19,9 +19,9 @@ namespace NadekoBot.Services.Administration public ConcurrentDictionary> IgnoredUsers = new ConcurrentDictionary>(); private readonly Logger _log; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; - public SlowmodeService(DiscordShardedClient client, IEnumerable gcs) + public SlowmodeService(DiscordSocketClient client, IEnumerable gcs) { _log = LogManager.GetCurrentClassLogger(); _client = client; diff --git a/src/NadekoBot/Services/Administration/SelfService.cs b/src/NadekoBot/Services/Administration/SelfService.cs index f3148d5a..8e8a4a13 100644 --- a/src/NadekoBot/Services/Administration/SelfService.cs +++ b/src/NadekoBot/Services/Administration/SelfService.cs @@ -23,11 +23,11 @@ namespace NadekoBot.Services.Administration private readonly Logger _log; private readonly ILocalization _localization; private readonly NadekoStrings _strings; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly IBotCredentials _creds; private ImmutableArray> ownerChannels = new ImmutableArray>(); - public SelfService(DiscordShardedClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db, + public SelfService(DiscordSocketClient client, NadekoBot bot, CommandHandler cmdHandler, DbService db, BotConfig bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds) { _bot = bot; @@ -69,10 +69,7 @@ namespace NadekoBot.Services.Administration LoadOwnerChannels(); - if (!ownerChannels.Any()) - _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); - else - _log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels."); + }); } @@ -81,11 +78,9 @@ namespace NadekoBot.Services.Administration var hs = new HashSet(_creds.OwnerIds); var channels = new Dictionary>(); - foreach (var s in _client.Shards) + if (hs.Count > 0) { - if (hs.Count == 0) - break; - foreach (var g in s.Guilds) + foreach (var g in _client.Guilds) { if (hs.Count == 0) break; @@ -101,14 +96,19 @@ namespace NadekoBot.Services.Administration } } } - + ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key)) .Select(x => x.Value) .ToImmutableArray(); + + if (!ownerChannels.Any()) + _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); + else + _log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels."); } // forwards dms - public async Task LateExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg) + public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg) { if (msg.Channel is IDMChannel && ForwardDMs && ownerChannels.Length > 0) { diff --git a/src/NadekoBot/Services/Administration/VcRoleService.cs b/src/NadekoBot/Services/Administration/VcRoleService.cs index 49dbe9ff..10252833 100644 --- a/src/NadekoBot/Services/Administration/VcRoleService.cs +++ b/src/NadekoBot/Services/Administration/VcRoleService.cs @@ -14,11 +14,11 @@ namespace NadekoBot.Services.Administration { private readonly Logger _log; private readonly DbService _db; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; public ConcurrentDictionary> VcRoles { get; } - public VcRoleService(DiscordShardedClient client, IEnumerable gcs, DbService db) + public VcRoleService(DiscordSocketClient client, IEnumerable gcs, DbService db) { _log = LogManager.GetCurrentClassLogger(); _db = db; diff --git a/src/NadekoBot/Services/Administration/VplusTService.cs b/src/NadekoBot/Services/Administration/VplusTService.cs index 3d9e86cd..b4e3122d 100644 --- a/src/NadekoBot/Services/Administration/VplusTService.cs +++ b/src/NadekoBot/Services/Administration/VplusTService.cs @@ -20,12 +20,12 @@ namespace NadekoBot.Services.Administration public readonly ConcurrentHashSet VoicePlusTextCache; private readonly ConcurrentDictionary _guildLockObjects = new ConcurrentDictionary(); - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly NadekoStrings _strings; private readonly DbService _db; private readonly Logger _log; - public VplusTService(DiscordShardedClient client, IEnumerable gcs, NadekoStrings strings, + public VplusTService(DiscordSocketClient client, IEnumerable gcs, NadekoStrings strings, DbService db) { _client = client; diff --git a/src/NadekoBot/Services/ClashOfClans/ClashOfClansService.cs b/src/NadekoBot/Services/ClashOfClans/ClashOfClansService.cs index edb78512..042afa1b 100644 --- a/src/NadekoBot/Services/ClashOfClans/ClashOfClansService.cs +++ b/src/NadekoBot/Services/ClashOfClans/ClashOfClansService.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Services.ClashOfClans // shouldn't be here public class ClashOfClansService { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly DbService _db; private readonly ILocalization _localization; private readonly NadekoStrings _strings; @@ -25,7 +25,7 @@ namespace NadekoBot.Services.ClashOfClans public ConcurrentDictionary> ClashWars { get; set; } - public ClashOfClansService(DiscordShardedClient client, DbService db, ILocalization localization, NadekoStrings strings) + public ClashOfClansService(DiscordSocketClient client, DbService db, ILocalization localization, NadekoStrings strings) { _client = client; _db = db; diff --git a/src/NadekoBot/Services/CommandHandler.cs b/src/NadekoBot/Services/CommandHandler.cs index 2177ce01..a1de8871 100644 --- a/src/NadekoBot/Services/CommandHandler.cs +++ b/src/NadekoBot/Services/CommandHandler.cs @@ -28,7 +28,7 @@ namespace NadekoBot.Services { public const int GlobalCommandsCooldown = 750; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly CommandService _commandService; private readonly Logger _log; private readonly IBotCredentials _creds; @@ -48,7 +48,7 @@ namespace NadekoBot.Services public ConcurrentHashSet UsersOnShortCooldown { get; } = new ConcurrentHashSet(); private readonly Timer _clearUsersOnShortCooldown; - public CommandHandler(DiscordShardedClient client, DbService db, BotConfig bc, IEnumerable gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot) + public CommandHandler(DiscordSocketClient client, DbService db, BotConfig bc, IEnumerable gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot) { _client = client; _commandService = commandService; diff --git a/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs b/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs index 206b0bd9..bb7fb8d9 100644 --- a/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs +++ b/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs @@ -22,13 +22,13 @@ namespace NadekoBot.Services.CustomReactions private readonly Logger _log; private readonly DbService _db; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly PermissionService _perms; private readonly CommandHandler _cmd; private readonly BotConfig _bc; public CustomReactionsService(PermissionService perms, DbService db, - DiscordShardedClient client, CommandHandler cmd, BotConfig bc) + DiscordSocketClient client, CommandHandler cmd, BotConfig bc) { _log = LogManager.GetCurrentClassLogger(); _db = db; @@ -37,15 +37,12 @@ namespace NadekoBot.Services.CustomReactions _cmd = cmd; _bc = bc; - var sw = Stopwatch.StartNew(); using (var uow = _db.UnitOfWork) { var items = uow.CustomReactions.GetAll(); GuildReactions = new ConcurrentDictionary(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray())); GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray(); } - sw.Stop(); - _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); } public void ClearStats() => ReactionStats.Clear(); @@ -98,7 +95,7 @@ namespace NadekoBot.Services.CustomReactions return greaction; } - public async Task TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg) + public async Task TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg) { // maybe this message is a custom reaction var cr = await Task.Run(() => TryGetCustomReaction(msg)).ConfigureAwait(false); diff --git a/src/NadekoBot/Services/CustomReactions/Extensions.cs b/src/NadekoBot/Services/CustomReactions/Extensions.cs index e2c5481f..4d6d4d06 100644 --- a/src/NadekoBot/Services/CustomReactions/Extensions.cs +++ b/src/NadekoBot/Services/CustomReactions/Extensions.cs @@ -40,7 +40,7 @@ namespace NadekoBot.Services.CustomReactions } }, }; - public static Dictionary> placeholders = new Dictionary>() + public static Dictionary> placeholders = new Dictionary>() { {"%mention%", (ctx, client) => { return $"<@{client.CurrentUser.Id}>"; } }, {"%user%", (ctx, client) => { return ctx.Author.Mention; } }, @@ -94,7 +94,7 @@ namespace NadekoBot.Services.CustomReactions } } }; - private static string ResolveTriggerString(this string str, IUserMessage ctx, DiscordShardedClient client) + private static string ResolveTriggerString(this string str, IUserMessage ctx, DiscordSocketClient client) { foreach (var ph in placeholders) { @@ -104,7 +104,7 @@ namespace NadekoBot.Services.CustomReactions return str; } - private static async Task ResolveResponseStringAsync(this string str, IUserMessage ctx, DiscordShardedClient client, string resolvedTrigger) + private static async Task ResolveResponseStringAsync(this string str, IUserMessage ctx, DiscordSocketClient client, string resolvedTrigger) { foreach (var ph in placeholders) { @@ -127,13 +127,13 @@ namespace NadekoBot.Services.CustomReactions return str; } - public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client) + public static string TriggerWithContext(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client) => cr.Trigger.ResolveTriggerString(ctx, client); - public static Task ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client) + public static Task ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client) => cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client)); - public static async Task Send(this CustomReaction cr, IUserMessage context, DiscordShardedClient client, CustomReactionsService crs) + public static async Task Send(this CustomReaction cr, IUserMessage context, DiscordSocketClient client, CustomReactionsService crs) { var channel = cr.DmResponse ? await context.Author.CreateDMChannelAsync() : context.Channel; diff --git a/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs index cca54609..52332cfb 100644 --- a/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs @@ -11,7 +11,7 @@ namespace NadekoBot.Services.Database.Repositories GuildConfig For(ulong guildId, Func, IQueryable> includes = null); GuildConfig LogSettingsFor(ulong guildId); IEnumerable OldPermissionsForAll(); - IEnumerable GetAllGuildConfigs(); + IEnumerable GetAllGuildConfigs(List availableGuilds); IEnumerable GetAllFollowedStreams(); void SetCleverbotEnabled(ulong id, bool cleverbotEnabled); IEnumerable Permissionsv2ForAll(); diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index f3ed3566..25dd52fe 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -24,8 +24,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl } }; - public IEnumerable GetAllGuildConfigs() => - _set.Include(gc => gc.LogSetting) + public IEnumerable GetAllGuildConfigs(List availableGuilds) => + _set + .Where(gc => availableGuilds.Contains((long)gc.GuildId)) + .Include(gc => gc.LogSetting) .ThenInclude(ls => ls.IgnoredChannels) .Include(gc => gc.MutedUsers) .Include(gc => gc.CommandAliases) diff --git a/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs b/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs index 58b3a1e5..4903fd66 100644 --- a/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs +++ b/src/NadekoBot/Services/Discord/SocketMessageEventWrapper.cs @@ -12,7 +12,7 @@ namespace NadekoBot.Services.Discord public event Action OnReactionRemoved = delegate { }; public event Action OnReactionsCleared = delegate { }; - public ReactionEventWrapper(DiscordShardedClient client, IUserMessage msg) + public ReactionEventWrapper(DiscordSocketClient client, IUserMessage msg) { Message = msg ?? throw new ArgumentNullException(nameof(msg)); _client = client; @@ -69,7 +69,7 @@ namespace NadekoBot.Services.Discord } private bool disposing = false; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; public void Dispose() { diff --git a/src/NadekoBot/Services/Games/ChatterbotService.cs b/src/NadekoBot/Services/Games/ChatterbotService.cs index 8039b79d..ad295dec 100644 --- a/src/NadekoBot/Services/Games/ChatterbotService.cs +++ b/src/NadekoBot/Services/Games/ChatterbotService.cs @@ -15,14 +15,14 @@ namespace NadekoBot.Services.Games { public class ChatterBotService : IEarlyBlockingExecutor { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly Logger _log; private readonly PermissionService _perms; private readonly CommandHandler _cmd; public ConcurrentDictionary> ChatterBotGuilds { get; } - public ChatterBotService(DiscordShardedClient client, PermissionService perms, IEnumerable gcs, CommandHandler cmd) + public ChatterBotService(DiscordSocketClient client, PermissionService perms, IEnumerable gcs, CommandHandler cmd) { _client = client; _log = LogManager.GetCurrentClassLogger(); @@ -83,7 +83,7 @@ namespace NadekoBot.Services.Games return true; } - public async Task TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage usrMsg) + public async Task TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage usrMsg) { if (!(guild is SocketGuild sg)) return false; diff --git a/src/NadekoBot/Services/Games/GamesService.cs b/src/NadekoBot/Services/Games/GamesService.cs index 24139906..e677990b 100644 --- a/src/NadekoBot/Services/Games/GamesService.cs +++ b/src/NadekoBot/Services/Games/GamesService.cs @@ -23,7 +23,7 @@ namespace NadekoBot.Services.Games public readonly ImmutableArray EightBallResponses; private readonly Timer _t; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly NadekoStrings _strings; private readonly IImagesService _images; private readonly Logger _log; @@ -33,7 +33,7 @@ namespace NadekoBot.Services.Games public List TypingArticles { get; } = new List(); - public GamesService(DiscordShardedClient client, BotConfig bc, IEnumerable gcs, + public GamesService(DiscordSocketClient client, BotConfig bc, IEnumerable gcs, NadekoStrings strings, IImagesService images, CommandHandler cmdHandler) { _bc = bc; diff --git a/src/NadekoBot/Services/Games/Poll.cs b/src/NadekoBot/Services/Games/Poll.cs index 8feb4cb5..1a6bbf20 100644 --- a/src/NadekoBot/Services/Games/Poll.cs +++ b/src/NadekoBot/Services/Games/Poll.cs @@ -18,7 +18,7 @@ namespace NadekoBot.Services.Games private string[] answers { get; } private readonly ConcurrentDictionary _participants = new ConcurrentDictionary(); private readonly string _question; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly NadekoStrings _strings; private bool running = false; private HashSet _guildUsers; @@ -27,7 +27,7 @@ namespace NadekoBot.Services.Games public bool IsPublic { get; } - public Poll(DiscordShardedClient client, NadekoStrings strings, IUserMessage umsg, string question, IEnumerable enumerable, bool isPublic = false) + public Poll(DiscordSocketClient client, NadekoStrings strings, IUserMessage umsg, string question, IEnumerable enumerable, bool isPublic = false) { _client = client; _strings = strings; diff --git a/src/NadekoBot/Services/Games/PollService.cs b/src/NadekoBot/Services/Games/PollService.cs index a421bd77..ce8852a7 100644 --- a/src/NadekoBot/Services/Games/PollService.cs +++ b/src/NadekoBot/Services/Games/PollService.cs @@ -13,10 +13,10 @@ namespace NadekoBot.Services.Games { public ConcurrentDictionary ActivePolls = new ConcurrentDictionary(); private readonly Logger _log; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly NadekoStrings _strings; - public PollService(DiscordShardedClient client, NadekoStrings strings) + public PollService(DiscordSocketClient client, NadekoStrings strings) { _log = LogManager.GetCurrentClassLogger(); _client = client; @@ -45,7 +45,7 @@ namespace NadekoBot.Services.Games return false; } - public async Task TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg) + public async Task TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg) { if (guild == null) { diff --git a/src/NadekoBot/Services/GreetSettingsService.cs b/src/NadekoBot/Services/GreetSettingsService.cs index 6e2e630d..3296c602 100644 --- a/src/NadekoBot/Services/GreetSettingsService.cs +++ b/src/NadekoBot/Services/GreetSettingsService.cs @@ -17,10 +17,10 @@ namespace NadekoBot.Services private readonly DbService _db; public readonly ConcurrentDictionary GuildConfigsCache; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly Logger _log; - public GreetSettingsService(DiscordShardedClient client, IEnumerable guildConfigs, DbService db) + public GreetSettingsService(DiscordSocketClient client, IEnumerable guildConfigs, DbService db) { _db = db; _client = client; diff --git a/src/NadekoBot/Services/Help/HelpService.cs b/src/NadekoBot/Services/Help/HelpService.cs index 25a91f16..83b64927 100644 --- a/src/NadekoBot/Services/Help/HelpService.cs +++ b/src/NadekoBot/Services/Help/HelpService.cs @@ -24,7 +24,7 @@ namespace NadekoBot.Services.Help _strings = strings; } - public async Task LateExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg) + public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg) { try { diff --git a/src/NadekoBot/Services/IBotCredentials.cs b/src/NadekoBot/Services/IBotCredentials.cs index c6c42f87..7fa661bd 100644 --- a/src/NadekoBot/Services/IBotCredentials.cs +++ b/src/NadekoBot/Services/IBotCredentials.cs @@ -20,6 +20,7 @@ namespace NadekoBot.Services string OsuApiKey { get; } bool IsOwner(IUser u); + int TotalShards { get; } } public class DBConfig diff --git a/src/NadekoBot/Services/IImagesService.cs b/src/NadekoBot/Services/IImagesService.cs index 0a76175d..31e6c32a 100644 --- a/src/NadekoBot/Services/IImagesService.cs +++ b/src/NadekoBot/Services/IImagesService.cs @@ -18,6 +18,6 @@ namespace NadekoBot.Services ImmutableArray WifeMatrix { get; } ImmutableArray RategirlDot { get; } - TimeSpan Reload(); + void Reload(); } } diff --git a/src/NadekoBot/Services/Impl/ImagesService.cs b/src/NadekoBot/Services/Impl/ImagesService.cs index 4bce6148..95930464 100644 --- a/src/NadekoBot/Services/Impl/ImagesService.cs +++ b/src/NadekoBot/Services/Impl/ImagesService.cs @@ -47,12 +47,10 @@ namespace NadekoBot.Services.Impl this.Reload(); } - public TimeSpan Reload() + public void Reload() { try { - _log.Info("Loading images..."); - var sw = Stopwatch.StartNew(); Heads = File.ReadAllBytes(_headsPath).ToImmutableArray(); Tails = File.ReadAllBytes(_tailsPath).ToImmutableArray(); @@ -79,10 +77,6 @@ namespace NadekoBot.Services.Impl WifeMatrix = File.ReadAllBytes(_wifeMatrixPath).ToImmutableArray(); RategirlDot = File.ReadAllBytes(_rategirlDot).ToImmutableArray(); - - sw.Stop(); - _log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!"); - return sw.Elapsed; } catch (Exception ex) { diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index bcd4a092..5d93196d 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -13,7 +13,7 @@ namespace NadekoBot.Services.Impl { public class StatsService : IStatsService { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly IBotCredentials _creds; private readonly DateTime _started; @@ -36,7 +36,7 @@ namespace NadekoBot.Services.Impl private readonly Timer _carbonitexTimer; - public StatsService(DiscordShardedClient client, CommandHandler cmdHandler, IBotCredentials creds) + public StatsService(DiscordSocketClient client, CommandHandler cmdHandler, IBotCredentials creds) { _client = client; _creds = creds; @@ -121,31 +121,32 @@ namespace NadekoBot.Services.Impl return Task.CompletedTask; }; - _carbonitexTimer = new Timer(async (state) => - { - if (string.IsNullOrWhiteSpace(_creds.CarbonKey)) - return; - try - { - using (var http = new HttpClient()) - { - using (var content = new FormUrlEncodedContent( - new Dictionary { - { "servercount", _client.Guilds.Count.ToString() }, - { "key", _creds.CarbonKey }})) - { - content.Headers.Clear(); - content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); + //todo carbonitex update + //_carbonitexTimer = new Timer(async (state) => + //{ + // if (string.IsNullOrWhiteSpace(_creds.CarbonKey)) + // return; + // try + // { + // using (var http = new HttpClient()) + // { + // using (var content = new FormUrlEncodedContent( + // new Dictionary { + // { "servercount", _client.Guilds.Count.ToString() }, + // { "key", _creds.CarbonKey }})) + // { + // content.Headers.Clear(); + // content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); - await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false); - } - } - } - catch - { - // ignored - } - }, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); + // await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false); + // } + // } + // } + // catch + // { + // // ignored + // } + //}, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); } public void Initialize() diff --git a/src/NadekoBot/Services/LogSetup.cs b/src/NadekoBot/Services/LogSetup.cs new file mode 100644 index 00000000..159b447e --- /dev/null +++ b/src/NadekoBot/Services/LogSetup.cs @@ -0,0 +1,28 @@ +using NLog; +using NLog.Config; +using NLog.Targets; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.Services +{ + public class LogSetup + { + public static void SetupLogger() + { + var logConfig = new LoggingConfiguration(); + var consoleTarget = new ColoredConsoleTarget() + { + Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}" + }; + logConfig.AddTarget("Console", consoleTarget); + + logConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget)); + + LogManager.Configuration = logConfig; + } + } +} diff --git a/src/NadekoBot/Services/Permissions/CmdCdService.cs b/src/NadekoBot/Services/Permissions/CmdCdService.cs index 0a1cbf47..7a44a292 100644 --- a/src/NadekoBot/Services/Permissions/CmdCdService.cs +++ b/src/NadekoBot/Services/Permissions/CmdCdService.cs @@ -21,7 +21,7 @@ namespace NadekoBot.Services.Permissions v => new ConcurrentHashSet(v.CommandCooldowns))); } - public Task TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, + public Task TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName) { if (guild == null) diff --git a/src/NadekoBot/Services/Permissions/FilterService.cs b/src/NadekoBot/Services/Permissions/FilterService.cs index 2dbd375d..adbe0aee 100644 --- a/src/NadekoBot/Services/Permissions/FilterService.cs +++ b/src/NadekoBot/Services/Permissions/FilterService.cs @@ -41,7 +41,7 @@ namespace NadekoBot.Services.Permissions return words; } - public FilterService(DiscordShardedClient _client, IEnumerable gcs) + public FilterService(DiscordSocketClient _client, IEnumerable gcs) { _log = LogManager.GetCurrentClassLogger(); diff --git a/src/NadekoBot/Services/Permissions/GlobalPermissionService.cs b/src/NadekoBot/Services/Permissions/GlobalPermissionService.cs index 633a81a3..419f77f3 100644 --- a/src/NadekoBot/Services/Permissions/GlobalPermissionService.cs +++ b/src/NadekoBot/Services/Permissions/GlobalPermissionService.cs @@ -19,7 +19,7 @@ namespace NadekoBot.Services.Permissions BlockedCommands = new ConcurrentHashSet(bc.BlockedCommands.Select(x => x.Name)); } - public async Task TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName) + public async Task TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName) { await Task.Yield(); commandName = commandName.ToLowerInvariant(); diff --git a/src/NadekoBot/Services/Permissions/PermissionsService.cs b/src/NadekoBot/Services/Permissions/PermissionsService.cs index 765cb131..27b547be 100644 --- a/src/NadekoBot/Services/Permissions/PermissionsService.cs +++ b/src/NadekoBot/Services/Permissions/PermissionsService.cs @@ -1,4 +1,5 @@ -using Microsoft.EntityFrameworkCore; + +using Microsoft.EntityFrameworkCore; using NadekoBot.DataStructures.ModuleBehaviors; using NadekoBot.Services.Database.Models; using NLog; @@ -183,7 +184,7 @@ WHERE secondaryTargetName LIKE '.%' OR }); } - public async Task TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName) + public async Task TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName) { await Task.Yield(); if (guild == null) diff --git a/src/NadekoBot/Services/Searches/SearchesService.cs b/src/NadekoBot/Services/Searches/SearchesService.cs index 864c9522..8c98a22e 100644 --- a/src/NadekoBot/Services/Searches/SearchesService.cs +++ b/src/NadekoBot/Services/Searches/SearchesService.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Services.Searches { public class SearchesService { - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly IGoogleApiService _google; private readonly DbService _db; private readonly Logger _log; @@ -31,7 +31,7 @@ namespace NadekoBot.Services.Searches public List WowJokes { get; } = new List(); public List MagicItems { get; } = new List(); - public SearchesService(DiscordShardedClient client, IGoogleApiService google, DbService db) + public SearchesService(DiscordSocketClient client, IGoogleApiService google, DbService db) { _client = client; _google = google; diff --git a/src/NadekoBot/Services/Searches/StreamNotificationService.cs b/src/NadekoBot/Services/Searches/StreamNotificationService.cs index 3fdbb9ac..9b8480fc 100644 --- a/src/NadekoBot/Services/Searches/StreamNotificationService.cs +++ b/src/NadekoBot/Services/Searches/StreamNotificationService.cs @@ -20,10 +20,10 @@ namespace NadekoBot.Services.Searches private readonly ConcurrentDictionary _cachedStatuses = new ConcurrentDictionary(); private readonly DbService _db; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly NadekoStrings _strings; - public StreamNotificationService(DbService db, DiscordShardedClient client, NadekoStrings strings) + public StreamNotificationService(DbService db, DiscordSocketClient client, NadekoStrings strings) { _db = db; _client = client; diff --git a/src/NadekoBot/Services/Utility/MessageRepeaterService.cs b/src/NadekoBot/Services/Utility/MessageRepeaterService.cs index 57873ef1..cc402aa8 100644 --- a/src/NadekoBot/Services/Utility/MessageRepeaterService.cs +++ b/src/NadekoBot/Services/Utility/MessageRepeaterService.cs @@ -15,7 +15,7 @@ namespace NadekoBot.Services.Utility public ConcurrentDictionary> Repeaters { get; set; } public bool RepeaterReady { get; private set; } - public MessageRepeaterService(NadekoBot bot, DiscordShardedClient client, IEnumerable gcs) + public MessageRepeaterService(NadekoBot bot, DiscordSocketClient client, IEnumerable gcs) { var _ = Task.Run(async () => { diff --git a/src/NadekoBot/Services/Utility/RemindService.cs b/src/NadekoBot/Services/Utility/RemindService.cs index a6dd276b..545e8648 100644 --- a/src/NadekoBot/Services/Utility/RemindService.cs +++ b/src/NadekoBot/Services/Utility/RemindService.cs @@ -30,10 +30,10 @@ namespace NadekoBot.Services.Utility private readonly CancellationTokenSource cancelSource; private readonly CancellationToken cancelAllToken; private readonly BotConfig _config; - private readonly DiscordShardedClient _client; + private readonly DiscordSocketClient _client; private readonly DbService _db; - public RemindService(DiscordShardedClient client, BotConfig config, DbService db) + public RemindService(DiscordSocketClient client, BotConfig config, DbService db) { _config = config; _client = client; diff --git a/src/NadekoBot/Services/Utility/RepeatRunner.cs b/src/NadekoBot/Services/Utility/RepeatRunner.cs index 8c96dc8b..abfa21b1 100644 --- a/src/NadekoBot/Services/Utility/RepeatRunner.cs +++ b/src/NadekoBot/Services/Utility/RepeatRunner.cs @@ -22,7 +22,7 @@ namespace NadekoBot.Services.Utility private IUserMessage oldMsg = null; private Timer _t; - public RepeatRunner(DiscordShardedClient client, Repeater repeater) + public RepeatRunner(DiscordSocketClient client, Repeater repeater) { _log = LogManager.GetCurrentClassLogger(); Repeater = repeater; diff --git a/src/NadekoBot/Services/Utility/UtilityService.cs b/src/NadekoBot/Services/Utility/UtilityService.cs index 660984b2..14af97e8 100644 --- a/src/NadekoBot/Services/Utility/UtilityService.cs +++ b/src/NadekoBot/Services/Utility/UtilityService.cs @@ -13,9 +13,9 @@ namespace NadekoBot.Services.Utility { public readonly ConcurrentDictionary> Subscribers = new ConcurrentDictionary>(); - private DiscordShardedClient _client; + private DiscordSocketClient _client; - public CrossServerTextService(IEnumerable guildConfigs, DiscordShardedClient client) + public CrossServerTextService(IEnumerable guildConfigs, DiscordSocketClient client) { _client = client; _client.MessageReceived += Client_MessageReceived; diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs new file mode 100644 index 00000000..6db3aade --- /dev/null +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -0,0 +1,95 @@ +using NadekoBot.DataStructures.ShardCom; +using NadekoBot.Services; +using NadekoBot.Services.Impl; +using NLog; +using System; +using System.Diagnostics; +using System.Linq; +using System.Threading.Tasks; + +namespace NadekoBot +{ + public class ShardsCoordinator + { + private readonly BotCredentials Credentials; + private Process[] ShardProcesses; + private ShardComMessage[] Statuses; + private readonly Logger _log; + private readonly ShardComServer _comServer; + + public ShardsCoordinator() + { + LogSetup.SetupLogger(); + Credentials = new BotCredentials(); + ShardProcesses = new Process[Credentials.TotalShards]; + Statuses = new ShardComMessage[Credentials.TotalShards]; + _log = LogManager.GetCurrentClassLogger(); + + _comServer = new ShardComServer(); + _comServer.Start(); + + _comServer.OnDataReceived += _comServer_OnDataReceived; + } + + private Task _comServer_OnDataReceived(ShardComMessage msg) + { + Statuses[msg.ShardId] = msg; + if (msg.ConnectionState == Discord.ConnectionState.Disconnected || msg.ConnectionState == Discord.ConnectionState.Disconnecting) + _log.Error("!!! SHARD {0} IS IN {1} STATE", msg.ShardId, msg.ConnectionState); + return Task.CompletedTask; + } + + public async Task RunAsync(params string[] args) + { + var curProcessId = Process.GetCurrentProcess().Id; + for (int i = 0; i < Credentials.TotalShards; i++) + { + var p = Process.Start(new ProcessStartInfo() + { + FileName = "dotnet", + Arguments = $"run -c Debug -- {i} {curProcessId}", + }); + await Task.Delay(5000); + + //Task.Run(() => { while (!p.HasExited) _log.Info($"S-{i}|" + p.StandardOutput.ReadLine()); }); + //Task.Run(() => { while (!p.HasExited) _log.Error($"S-{i}|" + p.StandardError.ReadLine()); }); + } + } + + public async Task RunAndBlockAsync(params string[] args) + { + try + { + await RunAsync(args).ConfigureAwait(false); + } + catch (Exception ex) + { + _log.Error(ex); + } + await Task.Run(() => + { + string input; + while ((input = Console.ReadLine()?.ToLowerInvariant()) != "quit") + { + switch (input) + { + case "ls": + var groupStr = string.Join(",", Statuses + .Where(x => x != null) + .GroupBy(x => x.ConnectionState) + .Select(x => x.Count() + " " + x.Key)); + _log.Info(string.Join("\n", Statuses.Select(x => $"Shard {x.ShardId} is in {x.ConnectionState.ToString()} state with {x.Guilds} servers")) + "\n" + groupStr); + break; + default: + break; + } + } + }); + foreach (var p in ShardProcesses) + { + try { p.Kill(); } catch { } + try { p.Dispose(); } catch { } + } + } + } +} diff --git a/src/NadekoBot/_Extensions/Extensions.cs b/src/NadekoBot/_Extensions/Extensions.cs index cafb5d32..10e97e14 100644 --- a/src/NadekoBot/_Extensions/Extensions.cs +++ b/src/NadekoBot/_Extensions/Extensions.cs @@ -70,7 +70,7 @@ namespace NadekoBot.Extensions /// /// danny kamisama /// - public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordShardedClient client, int currentPage, Func pageFunc, int? lastPage = null, bool addPaginatedFooter = true) + public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordSocketClient client, int currentPage, Func pageFunc, int? lastPage = null, bool addPaginatedFooter = true) { var embed = pageFunc(currentPage); @@ -134,7 +134,7 @@ namespace NadekoBot.Extensions return embed.WithFooter(efb => efb.WithText(curPage.ToString())); } - public static ReactionEventWrapper OnReaction(this IUserMessage msg, DiscordShardedClient client, Action reactionAdded, Action reactionRemoved = null) + public static ReactionEventWrapper OnReaction(this IUserMessage msg, DiscordSocketClient client, Action reactionAdded, Action reactionRemoved = null) { if (reactionRemoved == null) reactionRemoved = delegate { }; From 01cf59d83eee75817deca4c8f0f1e7d6278f9c7a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Tue, 20 Jun 2017 04:23:11 +0200 Subject: [PATCH 04/26] Sharding over processes almost done --- .../Commands/CrossServerTextChannel.cs | 64 --------------- src/NadekoBot/Modules/Utility/Utility.cs | 79 +------------------ src/NadekoBot/NadekoBot.cs | 63 +++++++++------ src/NadekoBot/Program.cs | 8 +- src/NadekoBot/Properties/launchSettings.json | 3 +- .../Repositories/IGuildConfigRepository.cs | 4 +- .../Repositories/IReminderRepository.cs | 4 +- .../Impl/GuildConfigRepository.cs | 9 ++- .../Repositories/Impl/ReminderRepository.cs | 8 ++ .../Permissions/PermissionsService.cs | 23 +++--- .../Services/Searches/AnimeSearchService.cs | 1 + .../Searches/StreamNotificationService.cs | 2 +- .../Services/Utility/ConverterService.cs | 1 + .../Services/Utility/PatreonRewardsService.cs | 1 + .../Services/Utility/RemindService.cs | 4 +- .../Services/Utility/UtilityService.cs | 69 ---------------- src/NadekoBot/ShardsCoordinator.cs | 8 +- .../_strings/ResponseStrings.en-US.json | 3 - 18 files changed, 85 insertions(+), 269 deletions(-) delete mode 100644 src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs delete mode 100644 src/NadekoBot/Services/Utility/UtilityService.cs diff --git a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs b/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs deleted file mode 100644 index de917054..00000000 --- a/src/NadekoBot/Modules/Utility/Commands/CrossServerTextChannel.cs +++ /dev/null @@ -1,64 +0,0 @@ -using Discord; -using Discord.Commands; -using NadekoBot.Attributes; -using NadekoBot.Extensions; -using NadekoBot.Services; -using NadekoBot.Services.Utility; -using System.Collections.Concurrent; -using System.Threading.Tasks; - -namespace NadekoBot.Modules.Utility -{ - public partial class Utility - { - [Group] - public class CrossServerTextChannel : NadekoSubmodule - { - private readonly CrossServerTextService _service; - - public CrossServerTextChannel(CrossServerTextService service) - { - _service = service; - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [OwnerOnly] - public async Task Scsc() - { - var token = new NadekoRandom().Next(); - var set = new ConcurrentHashSet(); - if (_service.Subscribers.TryAdd(token, set)) - { - set.Add((ITextChannel) Context.Channel); - await ((IGuildUser) Context.User).SendConfirmAsync(GetText("csc_token"), token.ToString()) - .ConfigureAwait(false); - } - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.ManageGuild)] - public async Task Jcsc(int token) - { - ConcurrentHashSet set; - if (!_service.Subscribers.TryGetValue(token, out set)) - return; - set.Add((ITextChannel) Context.Channel); - await ReplyConfirmLocalized("csc_join").ConfigureAwait(false); - } - - [NadekoCommand, Usage, Description, Aliases] - [RequireContext(ContextType.Guild)] - [RequireUserPermission(GuildPermission.ManageGuild)] - public async Task Lcsc() - { - foreach (var subscriber in _service.Subscribers) - { - subscriber.Value.TryRemove((ITextChannel) Context.Channel); - } - await ReplyConfirmLocalized("csc_leave").ConfigureAwait(false); - } - } - } -} \ No newline at end of file diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 4fecdf5e..caf0e6b0 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -35,84 +35,7 @@ namespace NadekoBot.Modules.Utility _stats = stats; _creds = creds; _bot = bot; - } - - //[NadekoCommand, Usage, Description, Aliases] - //[RequireContext(ContextType.Guild)] - //public async Task Midorina([Remainder] string arg) - //{ - // var channel = (ITextChannel)Context.Channel; - - // var roleNames = arg?.Split(';'); - - // if (roleNames == null || roleNames.Length == 0) - // return; - - // var j = 0; - // var roles = roleNames.Select(x => Context.Guild.Roles.FirstOrDefault(r => String.Compare(r.Name, x, StringComparison.OrdinalIgnoreCase) == 0)) - // .Where(x => x != null) - // .Take(10) - // .ToArray(); - - // var rnd = new NadekoRandom(); - // var reactions = new[] { "🎬", "🐧", "🌍", "🌺", "🚀", "☀", "🌲", "🍒", "🐾", "🏀" } - // .OrderBy(x => rnd.Next()) - // .ToArray(); - - // var roleStrings = roles - // .Select(x => $"{reactions[j++]} -> {x.Name}"); - - // var msg = await Context.Channel.SendConfirmAsync("Pick a Role", - // string.Join("\n", roleStrings)).ConfigureAwait(false); - - // for (int i = 0; i < roles.Length; i++) - // { - // try { await msg.AddReactionAsync(reactions[i]).ConfigureAwait(false); } - // catch (Exception ex) { _log.Warn(ex); } - // await Task.Delay(1000).ConfigureAwait(false); - // } - - // msg.OnReaction((r) => Task.Run(async () => - // { - // try - // { - // var usr = r.User.GetValueOrDefault() as IGuildUser; - - // if (usr == null) - // return; - - // var index = Array.IndexOf(reactions, r.Emoji.Name); - // if (index == -1) - // return; - - // await usr.RemoveRolesAsync(roles[index]); - // } - // catch (Exception ex) - // { - // _log.Warn(ex); - // } - // }), (r) => Task.Run(async () => - // { - // try - // { - // var usr = r.User.GetValueOrDefault() as IGuildUser; - - // if (usr == null) - // return; - - // var index = Array.IndexOf(reactions, r.Emoji.Name); - // if (index == -1) - // return; - - // await usr.RemoveRolesAsync(roles[index]); - // } - // catch (Exception ex) - // { - // _log.Warn(ex); - // } - // })); - //} - + } [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 1c086a7e..24398fe3 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -65,7 +65,8 @@ namespace NadekoBot private const string _mutexName = @"Global\nadeko_shards_lock"; private readonly Semaphore sem = new Semaphore(1, 1, _mutexName); public int ShardId { get; } - private readonly Thread waitForParentKill; + public ShardsCoordinator ShardCoord { get; private set; } + private readonly ShardComClient _comClient = new ShardComClient(); public NadekoBot(int shardId, int parentProcessId) @@ -79,22 +80,6 @@ namespace NadekoBot _log = LogManager.GetCurrentClassLogger(); TerribleElevatedPermissionCheck(); - waitForParentKill = new Thread(new ThreadStart(() => - { - try - { - var p = Process.GetProcessById(parentProcessId); - if (p == null) - return; - p.WaitForExit(); - } - finally - { - Environment.Exit(10); - } - })); - waitForParentKill.Start(); - Credentials = new BotCredentials(); Db = new DbService(Credentials); @@ -120,13 +105,12 @@ namespace NadekoBot CaseSensitiveCommands = false, DefaultRunMode = RunMode.Async, }); - - //foundation services + Images = new ImagesService(); Currency = new CurrencyService(BotConfig, Db); GoogleApi = new GoogleApiService(Credentials); - StartSendingData(); + SetupShard(shardId, parentProcessId); #if GLOBAL_NADEKO Client.Log += Client_Log; @@ -152,9 +136,10 @@ namespace NadekoBot private void AddServices() { + var startingGuildIdList = Client.Guilds.Select(x => (long)x.Id).ToList(); using (var uow = Db.UnitOfWork) { - AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(Client.Guilds.Select(x => (long)x.Id).ToList()).ToImmutableArray(); + AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray(); } Localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db); Strings = new NadekoStrings(Localization); @@ -170,8 +155,7 @@ namespace NadekoBot //module services //todo 90 - autodiscover, DI, and add instead of manual like this #region utility - var crossServerTextService = new CrossServerTextService(AllGuildConfigs, Client); - var remindService = new RemindService(Client, BotConfig, Db); + var remindService = new RemindService(Client, BotConfig, Db, startingGuildIdList); var repeaterService = new MessageRepeaterService(this, Client, AllGuildConfigs); var converterService = new ConverterService(Db); var commandMapService = new CommandMapService(AllGuildConfigs); @@ -181,7 +165,7 @@ namespace NadekoBot #endregion #region permissions - var permissionsService = new PermissionService(Db, BotConfig, CommandHandler); + var permissionsService = new PermissionService(Client, Db, BotConfig, CommandHandler); var blacklistService = new BlacklistService(BotConfig); var cmdcdsService = new CmdCdService(AllGuildConfigs); var filterService = new FilterService(Client, AllGuildConfigs); @@ -241,7 +225,6 @@ namespace NadekoBot .Add(CommandHandler) .Add(Db) //modules - .Add(crossServerTextService) .Add(commandMapService) .Add(remindService) .Add(repeaterService) @@ -375,7 +358,10 @@ namespace NadekoBot public async Task RunAndBlockAsync(params string[] args) { await RunAsync(args).ConfigureAwait(false); - await Task.Delay(-1).ConfigureAwait(false); + if (ShardCoord != null) + await ShardCoord.RunAndBlockAsync(); + else + await Task.Delay(-1).ConfigureAwait(false); } private void TerribleElevatedPermissionCheck() @@ -392,5 +378,30 @@ namespace NadekoBot Environment.Exit(2); } } + + private void SetupShard(int shardId, int parentProcessId) + { + if (shardId != 0) + { + new Thread(new ThreadStart(() => + { + try + { + var p = Process.GetProcessById(parentProcessId); + if (p == null) + return; + p.WaitForExit(); + } + finally + { + Environment.Exit(10); + } + })).Start(); + } + else + { + ShardCoord = new ShardsCoordinator(); + } + } } } diff --git a/src/NadekoBot/Program.cs b/src/NadekoBot/Program.cs index 20f3a052..a45affcc 100644 --- a/src/NadekoBot/Program.cs +++ b/src/NadekoBot/Program.cs @@ -4,12 +4,10 @@ { public static void Main(string[] args) { - if (args.Length == 0) - return; - if (args[0].ToLowerInvariant() == "main") - new ShardsCoordinator().RunAndBlockAsync(args).GetAwaiter().GetResult(); - else if (int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId)) + if (args.Length == 2 && int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId)) new NadekoBot(shardId, parentProcessId).RunAndBlockAsync(args).GetAwaiter().GetResult(); + else + new NadekoBot(0, 0).RunAndBlockAsync(args).GetAwaiter().GetResult(); } } } diff --git a/src/NadekoBot/Properties/launchSettings.json b/src/NadekoBot/Properties/launchSettings.json index 77336a17..b532770a 100644 --- a/src/NadekoBot/Properties/launchSettings.json +++ b/src/NadekoBot/Properties/launchSettings.json @@ -1,8 +1,7 @@ { "profiles": { "NadekoBot": { - "commandName": "Project", - "commandLineArgs": "main" + "commandName": "Project" } } } \ No newline at end of file diff --git a/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs index 52332cfb..e56a9026 100644 --- a/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/IGuildConfigRepository.cs @@ -12,9 +12,9 @@ namespace NadekoBot.Services.Database.Repositories GuildConfig LogSettingsFor(ulong guildId); IEnumerable OldPermissionsForAll(); IEnumerable GetAllGuildConfigs(List availableGuilds); - IEnumerable GetAllFollowedStreams(); + IEnumerable GetAllFollowedStreams(List included); void SetCleverbotEnabled(ulong id, bool cleverbotEnabled); - IEnumerable Permissionsv2ForAll(); + IEnumerable Permissionsv2ForAll(List include); GuildConfig GcWithPermissionsv2For(ulong guildId); } } diff --git a/src/NadekoBot/Services/Database/Repositories/IReminderRepository.cs b/src/NadekoBot/Services/Database/Repositories/IReminderRepository.cs index 7c643ec7..07eec33f 100644 --- a/src/NadekoBot/Services/Database/Repositories/IReminderRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/IReminderRepository.cs @@ -1,9 +1,11 @@ using NadekoBot.Services.Database.Models; +using System.Collections; +using System.Collections.Generic; namespace NadekoBot.Services.Database.Repositories { public interface IReminderRepository : IRepository { - + IEnumerable GetIncludedReminders(List guildIds); } } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 25dd52fe..37d2af60 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -136,9 +136,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl return query.ToList(); } - public IEnumerable Permissionsv2ForAll() + public IEnumerable Permissionsv2ForAll(List include) { var query = _set + .Where(x => include.Contains((long)x.GuildId)) .Include(gc => gc.Permissions); return query.ToList(); @@ -169,8 +170,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl return config; } - public IEnumerable GetAllFollowedStreams() => - _set.Include(gc => gc.FollowedStreams) + public IEnumerable GetAllFollowedStreams(List included) => + _set + .Where(gc => included.Contains((long)gc.GuildId)) + .Include(gc => gc.FollowedStreams) .SelectMany(gc => gc.FollowedStreams) .ToList(); diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/ReminderRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/ReminderRepository.cs index fc7c28ff..b1a0e2a0 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/ReminderRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/ReminderRepository.cs @@ -1,5 +1,8 @@ using NadekoBot.Services.Database.Models; using Microsoft.EntityFrameworkCore; +using System; +using System.Collections.Generic; +using System.Linq; namespace NadekoBot.Services.Database.Repositories.Impl { @@ -8,5 +11,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl public ReminderRepository(DbContext context) : base(context) { } + + public IEnumerable GetIncludedReminders(List guildIds) + { + return _set.Where(x => guildIds.Contains((long)x.ServerId)).ToList(); + } } } diff --git a/src/NadekoBot/Services/Permissions/PermissionsService.cs b/src/NadekoBot/Services/Permissions/PermissionsService.cs index 27b547be..7ca39a03 100644 --- a/src/NadekoBot/Services/Permissions/PermissionsService.cs +++ b/src/NadekoBot/Services/Permissions/PermissionsService.cs @@ -24,7 +24,7 @@ namespace NadekoBot.Services.Permissions public ConcurrentDictionary Cache { get; } = new ConcurrentDictionary(); - public PermissionService(DbService db, BotConfig bc, CommandHandler cmd) + public PermissionService(DiscordSocketClient client, DbService db, BotConfig bc, CommandHandler cmd) { _log = LogManager.GetCurrentClassLogger(); _db = db; @@ -32,18 +32,23 @@ namespace NadekoBot.Services.Permissions var sw = Stopwatch.StartNew(); TryMigratePermissions(bc); - using (var uow = _db.UnitOfWork) + + client.Ready += delegate { - foreach (var x in uow.GuildConfigs.Permissionsv2ForAll()) + using (var uow = _db.UnitOfWork) { - Cache.TryAdd(x.GuildId, new PermissionCache() + foreach (var x in uow.GuildConfigs.Permissionsv2ForAll(client.Guilds.Select(x => (long)x.Id).ToList())) { - Verbose = x.VerbosePermissions, - PermRole = x.PermissionRole, - Permissions = new PermissionsCollection(x.Permissions) - }); + Cache.TryAdd(x.GuildId, new PermissionCache() + { + Verbose = x.VerbosePermissions, + PermRole = x.PermissionRole, + Permissions = new PermissionsCollection(x.Permissions) + }); + } } - } + return Task.CompletedTask; + }; sw.Stop(); _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); diff --git a/src/NadekoBot/Services/Searches/AnimeSearchService.cs b/src/NadekoBot/Services/Searches/AnimeSearchService.cs index 71820506..2e4ef756 100644 --- a/src/NadekoBot/Services/Searches/AnimeSearchService.cs +++ b/src/NadekoBot/Services/Searches/AnimeSearchService.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; namespace NadekoBot.Services.Searches { + //todo move to the website public class AnimeSearchService { private readonly Timer _anilistTokenRefresher; diff --git a/src/NadekoBot/Services/Searches/StreamNotificationService.cs b/src/NadekoBot/Services/Searches/StreamNotificationService.cs index 9b8480fc..a5846362 100644 --- a/src/NadekoBot/Services/Searches/StreamNotificationService.cs +++ b/src/NadekoBot/Services/Searches/StreamNotificationService.cs @@ -35,7 +35,7 @@ namespace NadekoBot.Services.Searches IEnumerable streams; using (var uow = _db.UnitOfWork) { - streams = uow.GuildConfigs.GetAllFollowedStreams(); + streams = uow.GuildConfigs.GetAllFollowedStreams(client.Guilds.Select(x => (long)x.Id).ToList()); } await Task.WhenAll(streams.Select(async fs => diff --git a/src/NadekoBot/Services/Utility/ConverterService.cs b/src/NadekoBot/Services/Utility/ConverterService.cs index 38fc7f9a..b7388335 100644 --- a/src/NadekoBot/Services/Utility/ConverterService.cs +++ b/src/NadekoBot/Services/Utility/ConverterService.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; namespace NadekoBot.Services.Utility { + //todo periodically load from the database, update only on shard 0 public class ConverterService { public List Units { get; set; } = new List(); diff --git a/src/NadekoBot/Services/Utility/PatreonRewardsService.cs b/src/NadekoBot/Services/Utility/PatreonRewardsService.cs index e8202d84..0f7105b7 100644 --- a/src/NadekoBot/Services/Utility/PatreonRewardsService.cs +++ b/src/NadekoBot/Services/Utility/PatreonRewardsService.cs @@ -12,6 +12,7 @@ using System.Threading.Tasks; namespace NadekoBot.Services.Utility { + //todo periodically load from the database, update only on shard 0 public class PatreonRewardsService { private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); diff --git a/src/NadekoBot/Services/Utility/RemindService.cs b/src/NadekoBot/Services/Utility/RemindService.cs index 545e8648..16d6d451 100644 --- a/src/NadekoBot/Services/Utility/RemindService.cs +++ b/src/NadekoBot/Services/Utility/RemindService.cs @@ -33,7 +33,7 @@ namespace NadekoBot.Services.Utility private readonly DiscordSocketClient _client; private readonly DbService _db; - public RemindService(DiscordSocketClient client, BotConfig config, DbService db) + public RemindService(DiscordSocketClient client, BotConfig config, DbService db, List guilds) { _config = config; _client = client; @@ -45,7 +45,7 @@ namespace NadekoBot.Services.Utility List reminders; using (var uow = _db.UnitOfWork) { - reminders = uow.Reminders.GetAll().ToList(); + reminders = uow.Reminders.GetIncludedReminders(guilds).ToList(); } RemindMessageFormat = _config.RemindMessageFormat; diff --git a/src/NadekoBot/Services/Utility/UtilityService.cs b/src/NadekoBot/Services/Utility/UtilityService.cs deleted file mode 100644 index 14af97e8..00000000 --- a/src/NadekoBot/Services/Utility/UtilityService.cs +++ /dev/null @@ -1,69 +0,0 @@ -using Discord; -using Discord.WebSocket; -using NadekoBot.Extensions; -using NadekoBot.Services.Database.Models; -using System.Collections.Concurrent; -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace NadekoBot.Services.Utility -{ - public class CrossServerTextService - { - public readonly ConcurrentDictionary> Subscribers = - new ConcurrentDictionary>(); - private DiscordSocketClient _client; - - public CrossServerTextService(IEnumerable guildConfigs, DiscordSocketClient client) - { - _client = client; - _client.MessageReceived += Client_MessageReceived; - } - - private Task Client_MessageReceived(SocketMessage imsg) - { - var _ = Task.Run(async () => { - try - { - if (imsg.Author.IsBot) - return; - var msg = imsg as IUserMessage; - if (msg == null) - return; - var channel = imsg.Channel as ITextChannel; - if (channel == null) - return; - if (msg.Author.Id == _client.CurrentUser.Id) return; - foreach (var subscriber in Subscribers) - { - var set = subscriber.Value; - if (!set.Contains(channel)) - continue; - foreach (var chan in set.Except(new[] { channel })) - { - try - { - await chan.SendMessageAsync(GetMessage(channel, (IGuildUser)msg.Author, - msg)).ConfigureAwait(false); - } - catch - { - // ignored - } - } - } - } - catch - { - // ignored - } - }); - - return Task.CompletedTask; - } - - private string GetMessage(ITextChannel channel, IGuildUser user, IUserMessage message) => - $"**{channel.Guild.Name} | {channel.Name}** `{user.Username}`: " + message.Content.SanitizeMentions(); - } -} diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs index 6db3aade..acdac540 100644 --- a/src/NadekoBot/ShardsCoordinator.cs +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -39,10 +39,10 @@ namespace NadekoBot return Task.CompletedTask; } - public async Task RunAsync(params string[] args) + public async Task RunAsync() { var curProcessId = Process.GetCurrentProcess().Id; - for (int i = 0; i < Credentials.TotalShards; i++) + for (int i = 1; i < Credentials.TotalShards; i++) { var p = Process.Start(new ProcessStartInfo() { @@ -56,11 +56,11 @@ namespace NadekoBot } } - public async Task RunAndBlockAsync(params string[] args) + public async Task RunAndBlockAsync() { try { - await RunAsync(args).ConfigureAwait(false); + await RunAsync().ConfigureAwait(false); } catch (Exception ex) { diff --git a/src/NadekoBot/_strings/ResponseStrings.en-US.json b/src/NadekoBot/_strings/ResponseStrings.en-US.json index 98df2300..d1863403 100644 --- a/src/NadekoBot/_strings/ResponseStrings.en-US.json +++ b/src/NadekoBot/_strings/ResponseStrings.en-US.json @@ -613,9 +613,6 @@ "utility_convert_not_found": "Cannot convert {0} to {1}: units not found", "utility_convert_type_error": "Cannot convert {0} to {1}: types of unit are not equal", "utility_created_at": "Created at", - "utility_csc_join": "Joined cross server channel.", - "utility_csc_leave": "Left cross server channel.", - "utility_csc_token": "This is your CSC token", "utility_custom_emojis": "Custom emojis", "utility_error": "Error", "utility_features": "Features", From c709680413235ab995f45bddcbc8269bced2c31b Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 21 Jun 2017 15:14:08 +0200 Subject: [PATCH 05/26] fix --- .../DataStructures/Shard0Precondition.cs | 22 +++++++++++++++++++ src/NadekoBot/NadekoBot.cs | 3 ++- 2 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 src/NadekoBot/DataStructures/Shard0Precondition.cs diff --git a/src/NadekoBot/DataStructures/Shard0Precondition.cs b/src/NadekoBot/DataStructures/Shard0Precondition.cs new file mode 100644 index 00000000..eaa5c591 --- /dev/null +++ b/src/NadekoBot/DataStructures/Shard0Precondition.cs @@ -0,0 +1,22 @@ +using Discord.Commands; +using Discord.WebSocket; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace NadekoBot.DataStructures +{ + public class Shard0Precondition : PreconditionAttribute + { + public override Task CheckPermissions(ICommandContext context, CommandInfo command, IServiceProvider services) + { + var c = (DiscordSocketClient)context.Client; + if (c.ShardId == 0) + return Task.FromResult(PreconditionResult.FromSuccess()); + else + return Task.FromResult(PreconditionResult.FromError("Must be ran from shard #0")); + } + } +} diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index a7a32fce..d6b675de 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -224,7 +224,7 @@ namespace NadekoBot .Add(Currency) .Add(CommandHandler) .Add(Db) - //modules + //modules .Add(commandMapService) .Add(remindService) .Add(repeaterService) @@ -261,6 +261,7 @@ namespace NadekoBot .Add(filterService) .Add(globalPermsService) .Add(pokemonService) + .Add(this) .Build(); CommandHandler.AddServices(Services); From 4862564c74236a8f6393e5a4694b00fb0be87f1b Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 21 Jun 2017 23:12:24 +0200 Subject: [PATCH 06/26] disabled private poll, removed shardid command --- .../Modules/Games/Commands/PollCommands.cs | 7 ++- src/NadekoBot/Modules/Utility/Utility.cs | 62 +++++++++---------- src/NadekoBot/Services/IBotCredentials.cs | 2 + src/NadekoBot/Services/Impl/BotCredentials.cs | 19 ++++-- src/NadekoBot/ShardsCoordinator.cs | 11 ++-- src/NadekoBot/credentials_example.json | 3 +- 6 files changed, 56 insertions(+), 48 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs index 1cf5b951..27dbb03c 100644 --- a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs @@ -44,9 +44,14 @@ namespace NadekoBot.Modules.Games await Context.Channel.EmbedAsync(poll.GetStats(GetText("current_poll_results"))); } - + //todo enable private polls, or completely remove them private async Task InternalStartPoll(string arg, bool isPublic = false) { + if (isPublic == false) + { + await ReplyErrorLocalized($"Temporarily disabled. Use `{Prefix}ppoll`"); + return; + } if(await _polls.StartPoll((ITextChannel)Context.Channel, Context.Message, arg, isPublic) == false) await ReplyErrorLocalized("poll_already_running").ConfigureAwait(false); } diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index caf0e6b0..1b0276e6 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -18,6 +18,7 @@ using Discord.WebSocket; using System.Diagnostics; using Color = Discord.Color; using NadekoBot.Services; +using NadekoBot.DataStructures; namespace NadekoBot.Modules.Utility { @@ -277,48 +278,41 @@ namespace NadekoBot.Modules.Utility await Context.Channel.SendConfirmAsync($"{Context.User.Mention} https://discord.gg/{invite.Code}"); } - //todo 2 shard commands - //[NadekoCommand, Usage, Description, Aliases] - //public async Task ShardStats(int page = 1) - //{ - // if (--page < 0) - // return; - // var status = string.Join(", ", _client.Shards.GroupBy(x => x.ConnectionState) - // .Select(x => $"{x.Count()} {x.Key}") - // .ToArray()); + [NadekoCommand, Usage, Description, Aliases] + [Shard0Precondition] + public async Task ShardStats(int page = 1) + { + if (--page < 0) + return; - // var allShardStrings = _client.Shards - // .Select(x => - // GetText("shard_stats_txt", x.ShardId.ToString(), - // Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString()))) - // .ToArray(); + var status = string.Join(", ", _bot.ShardCoord.Statuses.GroupBy(x => x.ConnectionState) + .Select(x => $"{x.Count()} {x.Key}") + .ToArray()); + + var allShardStrings = _bot.ShardCoord.Statuses + .Select(x => + GetText("shard_stats_txt", x.ShardId.ToString(), + Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.ToString()))) + .ToArray(); - // await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) => - // { + await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) => + { - // var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25)); + var str = string.Join("\n", allShardStrings.Skip(25 * curPage).Take(25)); - // if (string.IsNullOrWhiteSpace(str)) - // str = GetText("no_shards_on_page"); + if (string.IsNullOrWhiteSpace(str)) + str = GetText("no_shards_on_page"); - // return new EmbedBuilder() - // .WithAuthor(a => a.WithName(GetText("shard_stats"))) - // .WithTitle(status) - // .WithOkColor() - // .WithDescription(str); - // }, allShardStrings.Length / 25); - //} - - //[NadekoCommand, Usage, Description, Aliases] - //public async Task ShardId(IGuild guild) - //{ - // var shardId = _client.GetShardIdFor(guild); - - // await Context.Channel.SendConfirmAsync(shardId.ToString()).ConfigureAwait(false); - //} + return new EmbedBuilder() + .WithAuthor(a => a.WithName(GetText("shard_stats"))) + .WithTitle(status) + .WithOkColor() + .WithDescription(str); + }, allShardStrings.Length / 25); + } [NadekoCommand, Usage, Description, Aliases] public async Task Stats() diff --git a/src/NadekoBot/Services/IBotCredentials.cs b/src/NadekoBot/Services/IBotCredentials.cs index d7a7073c..e0c271b5 100644 --- a/src/NadekoBot/Services/IBotCredentials.cs +++ b/src/NadekoBot/Services/IBotCredentials.cs @@ -20,6 +20,8 @@ namespace NadekoBot.Services bool IsOwner(IUser u); int TotalShards { get; } + string ShardRunCommand { get; } + string ShardRunArguments { get; } } public class DBConfig diff --git a/src/NadekoBot/Services/Impl/BotCredentials.cs b/src/NadekoBot/Services/Impl/BotCredentials.cs index 92ae20c1..3517a298 100644 --- a/src/NadekoBot/Services/Impl/BotCredentials.cs +++ b/src/NadekoBot/Services/Impl/BotCredentials.cs @@ -30,20 +30,22 @@ namespace NadekoBot.Services.Impl public int TotalShards { get; } public string CarbonKey { get; } - public string credsFileName { get; } = Path.Combine(Directory.GetCurrentDirectory(), "credentials.json"); + private readonly string _credsFileName = Path.Combine(Directory.GetCurrentDirectory(), "credentials.json"); public string PatreonAccessToken { get; } + public string ShardRunCommand { get; } + public string ShardRunArguments { get; } public BotCredentials() { _log = LogManager.GetCurrentClassLogger(); try { File.WriteAllText("./credentials_example.json", JsonConvert.SerializeObject(new CredentialsModel(), Formatting.Indented)); } catch { } - if(!File.Exists(credsFileName)) + if(!File.Exists(_credsFileName)) _log.Warn($"credentials.json is missing. Attempting to load creds from environment variables prefixed with 'NadekoBot_'. Example is in {Path.GetFullPath("./credentials_example.json")}"); try { var configBuilder = new ConfigurationBuilder(); - configBuilder.AddJsonFile(credsFileName, true) + configBuilder.AddJsonFile(_credsFileName, true) .AddEnvironmentVariables("NadekoBot_"); var data = configBuilder.Build(); @@ -61,13 +63,19 @@ namespace NadekoBot.Services.Impl MashapeKey = data[nameof(MashapeKey)]; OsuApiKey = data[nameof(OsuApiKey)]; PatreonAccessToken = data[nameof(PatreonAccessToken)]; + ShardRunCommand = data[nameof(ShardRunCommand)]; + ShardRunArguments = data[nameof(ShardRunArguments)]; + + if (string.IsNullOrWhiteSpace(ShardRunCommand)) + ShardRunCommand = "dotnet"; + if (string.IsNullOrWhiteSpace(ShardRunArguments)) + ShardRunArguments = "run -c Release -- {0} {1}"; int ts = 1; int.TryParse(data[nameof(TotalShards)], out ts); TotalShards = ts < 1 ? 1 : ts; - ulong clId = 0; - ulong.TryParse(data[nameof(ClientId)], out clId); + ulong.TryParse(data[nameof(ClientId)], out ulong clId); ClientId = clId; //var scId = data[nameof(SoundCloudClientId)]; @@ -107,6 +115,7 @@ namespace NadekoBot.Services.Impl public DBConfig Db { get; set; } = new DBConfig("sqlite", "Filename=./data/NadekoBot.db"); public int TotalShards { get; set; } = 1; public string PatreonAccessToken { get; set; } = ""; + public string ShardRunCommand { get; set; } = ""; } private class DbModel diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs index acdac540..395ad71d 100644 --- a/src/NadekoBot/ShardsCoordinator.cs +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -13,7 +13,7 @@ namespace NadekoBot { private readonly BotCredentials Credentials; private Process[] ShardProcesses; - private ShardComMessage[] Statuses; + public ShardComMessage[] Statuses { get; } private readonly Logger _log; private readonly ShardComServer _comServer; @@ -35,7 +35,7 @@ namespace NadekoBot { Statuses[msg.ShardId] = msg; if (msg.ConnectionState == Discord.ConnectionState.Disconnected || msg.ConnectionState == Discord.ConnectionState.Disconnecting) - _log.Error("!!! SHARD {0} IS IN {1} STATE", msg.ShardId, msg.ConnectionState); + _log.Error("!!! SHARD {0} IS IN {1} STATE", msg.ShardId, msg.ConnectionState.ToString()); return Task.CompletedTask; } @@ -46,13 +46,10 @@ namespace NadekoBot { var p = Process.Start(new ProcessStartInfo() { - FileName = "dotnet", - Arguments = $"run -c Debug -- {i} {curProcessId}", + FileName = Credentials.ShardRunCommand, + Arguments = string.Format(Credentials.ShardRunArguments, i, curProcessId) }); await Task.Delay(5000); - - //Task.Run(() => { while (!p.HasExited) _log.Info($"S-{i}|" + p.StandardOutput.ReadLine()); }); - //Task.Run(() => { while (!p.HasExited) _log.Error($"S-{i}|" + p.StandardError.ReadLine()); }); } } diff --git a/src/NadekoBot/credentials_example.json b/src/NadekoBot/credentials_example.json index 912b452a..7c7e4095 100644 --- a/src/NadekoBot/credentials_example.json +++ b/src/NadekoBot/credentials_example.json @@ -15,5 +15,6 @@ "ConnectionString": "Filename=./data/NadekoBot.db" }, "TotalShards": 1, - "PatreonAccessToken": "" + "PatreonAccessToken": "", + "ShardRunCommand": "" } \ No newline at end of file From 85e183999141682cca9ed773ae5ac08688f10367 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 21 Jun 2017 23:31:47 +0200 Subject: [PATCH 07/26] don't load owner channels --- src/NadekoBot/Services/Administration/SelfService.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Services/Administration/SelfService.cs b/src/NadekoBot/Services/Administration/SelfService.cs index 8e8a4a13..0c5b6e48 100644 --- a/src/NadekoBot/Services/Administration/SelfService.cs +++ b/src/NadekoBot/Services/Administration/SelfService.cs @@ -67,9 +67,8 @@ namespace NadekoBot.Services.Administration _client.Guilds.SelectMany(g => g.Users); - LoadOwnerChannels(); - - + //todo load owner channels + //LoadOwnerChannels(); }); } From 4b57d874bac04818d44a643eb51521cef7272829 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 21 Jun 2017 23:34:29 +0200 Subject: [PATCH 08/26] Fixed compile error --- src/NadekoBot/NadekoBot.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index d6b675de..9c1df1ab 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -28,6 +28,7 @@ using NadekoBot.Services.Help; using System.IO; using NadekoBot.Services.Pokemon; using NadekoBot.DataStructures.ShardCom; +using NadekoBot.DataStructures; namespace NadekoBot { @@ -335,13 +336,14 @@ namespace NadekoBot // .Select(x => x.Key + $"({x.Count()})"))); //unload modules which are not available on the public bot -#if GLOBAL_NADEKO +#if GLOBAL_NADEKO CommandService .Modules .ToArray() .Where(x => x.Preconditions.Any(y => y.GetType() == typeof(NoPublicBot))) .ForEach(x => CommandService.RemoveModuleAsync(x)); #endif + Ready = true; _log.Info($"Shard {ShardId} ready."); //_log.Info(await stats.Print().ConfigureAwait(false)); From f1bcbd91a3634cd8efa7f7dffd4154a45141aa24 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 21 Jun 2017 23:36:00 +0200 Subject: [PATCH 09/26] Another one --- src/NadekoBot/NadekoBot.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 9c1df1ab..e1223ec9 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -29,6 +29,7 @@ using System.IO; using NadekoBot.Services.Pokemon; using NadekoBot.DataStructures.ShardCom; using NadekoBot.DataStructures; +using NadekoBot.Extensions; namespace NadekoBot { From d2ea530c10541ae266d4fbc0c3b4f8b38cf70beb Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Wed, 21 Jun 2017 23:49:13 +0200 Subject: [PATCH 10/26] fix shard status nullrefs --- src/NadekoBot/Modules/Utility/Utility.cs | 8 +++--- src/NadekoBot/ShardsCoordinator.cs | 32 +++++++++++++++--------- 2 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 1b0276e6..c26e584e 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -285,12 +285,14 @@ namespace NadekoBot.Modules.Utility { if (--page < 0) return; - - var status = string.Join(", ", _bot.ShardCoord.Statuses.GroupBy(x => x.ConnectionState) + var statuses = _bot.ShardCoord.Statuses.ToArray(); + var status = string.Join(", ", statuses + .Where(x => x != null) + .GroupBy(x => x.ConnectionState) .Select(x => $"{x.Count()} {x.Key}") .ToArray()); - var allShardStrings = _bot.ShardCoord.Statuses + var allShardStrings = statuses .Select(x => GetText("shard_stats_txt", x.ShardId.ToString(), Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.ToString()))) diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs index 395ad71d..8ce8f6f6 100644 --- a/src/NadekoBot/ShardsCoordinator.cs +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -65,22 +65,30 @@ namespace NadekoBot } await Task.Run(() => { - string input; - while ((input = Console.ReadLine()?.ToLowerInvariant()) != "quit") + try { - switch (input) + string input; + while ((input = Console.ReadLine()?.ToLowerInvariant()) != "quit") { - case "ls": - var groupStr = string.Join(",", Statuses - .Where(x => x != null) - .GroupBy(x => x.ConnectionState) - .Select(x => x.Count() + " " + x.Key)); - _log.Info(string.Join("\n", Statuses.Select(x => $"Shard {x.ShardId} is in {x.ConnectionState.ToString()} state with {x.Guilds} servers")) + "\n" + groupStr); - break; - default: - break; + switch (input) + { + case "ls": + var groupStr = string.Join(",", Statuses + .ToArray() + .Where(x => x != null) + .GroupBy(x => x.ConnectionState) + .Select(x => x.Count() + " " + x.Key)); + _log.Info(string.Join("\n", Statuses.Select(x => $"Shard {x.ShardId} is in {x.ConnectionState.ToString()} state with {x.Guilds} servers")) + "\n" + groupStr); + break; + default: + break; + } } } + catch (Exception ex) + { + _log.Warn(ex); + } }); foreach (var p in ShardProcesses) { From ee72962ee5da3e4c01f404a712e5a3fa894f149f Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 22 Jun 2017 00:12:29 +0200 Subject: [PATCH 11/26] Possible database lock fix --- src/NadekoBot/Modules/Utility/Utility.cs | 5 +++-- src/NadekoBot/Services/Database/NadekoContext.cs | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index c26e584e..51f24efc 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -285,9 +285,10 @@ namespace NadekoBot.Modules.Utility { if (--page < 0) return; - var statuses = _bot.ShardCoord.Statuses.ToArray(); + var statuses = _bot.ShardCoord.Statuses.ToArray() + .Where(x => x != null); + var status = string.Join(", ", statuses - .Where(x => x != null) .GroupBy(x => x.ConnectionState) .Select(x => $"{x.Count()} {x.Key}") .ToArray()); diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index 9c084867..b61c9aa9 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -18,8 +18,9 @@ namespace NadekoBot.Services.Database public NadekoContext Create(DbContextFactoryOptions options) { var optionsBuilder = new DbContextOptionsBuilder(); - optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db"); - return new NadekoContext(optionsBuilder.Options); + optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db;Default Command Timeout=60000;Busy Timeout=60000"); + var ctx = new NadekoContext(optionsBuilder.Options); + return ctx; } } From d3c598ae01ddf5bfd37c57073e87130498d958b9 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 22 Jun 2017 00:22:50 +0200 Subject: [PATCH 12/26] Command Timeout set to 60 --- src/NadekoBot/Services/Database/NadekoContext.cs | 3 ++- src/NadekoBot/Services/DbService.cs | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NadekoBot/Services/Database/NadekoContext.cs b/src/NadekoBot/Services/Database/NadekoContext.cs index b61c9aa9..238130ed 100644 --- a/src/NadekoBot/Services/Database/NadekoContext.cs +++ b/src/NadekoBot/Services/Database/NadekoContext.cs @@ -18,8 +18,9 @@ namespace NadekoBot.Services.Database public NadekoContext Create(DbContextFactoryOptions options) { var optionsBuilder = new DbContextOptionsBuilder(); - optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db;Default Command Timeout=60000;Busy Timeout=60000"); + optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db"); var ctx = new NadekoContext(optionsBuilder.Options); + ctx.Database.SetCommandTimeout(60); return ctx; } } diff --git a/src/NadekoBot/Services/DbService.cs b/src/NadekoBot/Services/DbService.cs index 81e56d1d..c8fab899 100644 --- a/src/NadekoBot/Services/DbService.cs +++ b/src/NadekoBot/Services/DbService.cs @@ -32,6 +32,7 @@ namespace NadekoBot.Services public NadekoContext GetDbContext() { var context = new NadekoContext(options); + context.Database.SetCommandTimeout(60); context.Database.Migrate(); context.EnsureSeedData(); From 2cad7f4475be6cb340de64d46f12b72ba3bec027 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 22 Jun 2017 00:47:29 +0200 Subject: [PATCH 13/26] small fixes --- src/NadekoBot/NadekoBot.cs | 5 +++-- src/NadekoBot/ShardsCoordinator.cs | 16 ++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index e1223ec9..53288c5c 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -292,7 +292,7 @@ namespace NadekoBot } finally { - _log.Info("Shard {0} logged in ...", ShardId); + _log.Info("Shard {0} logged in.", ShardId); sem.Release(); } return Task.CompletedTask; @@ -306,6 +306,7 @@ namespace NadekoBot public async Task RunAsync(params string[] args) { + if(ShardId == 0) _log.Info("Starting NadekoBot v" + StatsService.BotVersion); var sw = Stopwatch.StartNew(); @@ -316,7 +317,7 @@ namespace NadekoBot AddServices(); sw.Stop(); - _log.Info($"Shard {ShardId} connected in {sw.Elapsed.TotalSeconds:F2} s"); + _log.Info($"Shard {ShardId} connected in {sw.Elapsed.TotalSeconds:F2}s"); var stats = Services.GetService(); stats.Initialize(); diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs index 8ce8f6f6..9f848389 100644 --- a/src/NadekoBot/ShardsCoordinator.cs +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -49,7 +49,7 @@ namespace NadekoBot FileName = Credentials.ShardRunCommand, Arguments = string.Format(Credentials.ShardRunArguments, i, curProcessId) }); - await Task.Delay(5000); + await Task.Delay(6500); } } @@ -65,10 +65,10 @@ namespace NadekoBot } await Task.Run(() => { - try + string input; + while ((input = Console.ReadLine()?.ToLowerInvariant()) != "quit") { - string input; - while ((input = Console.ReadLine()?.ToLowerInvariant()) != "quit") + try { switch (input) { @@ -84,10 +84,10 @@ namespace NadekoBot break; } } - } - catch (Exception ex) - { - _log.Warn(ex); + catch (Exception ex) + { + _log.Warn(ex); + } } }); foreach (var p in ShardProcesses) From 0aa65b29534dc1fe376cb4b44b789d87409c381a Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 22 Jun 2017 03:39:26 +0200 Subject: [PATCH 14/26] Fixes to remind and shardstats --- .../Modules/Utility/Commands/Remind.cs | 4 +- src/NadekoBot/NadekoBot.cs | 3 + .../Services/Administration/SelfService.cs | 58 +++++++++---------- src/NadekoBot/ShardsCoordinator.cs | 5 +- 4 files changed, 38 insertions(+), 32 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/Remind.cs b/src/NadekoBot/Modules/Utility/Commands/Remind.cs index 448ec424..ce046467 100644 --- a/src/NadekoBot/Modules/Utility/Commands/Remind.cs +++ b/src/NadekoBot/Modules/Utility/Commands/Remind.cs @@ -33,7 +33,7 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] - [Priority(1)] + [Priority(0)] public async Task Remind(MeOrHere meorhere, string timeStr, [Remainder] string message) { ulong target; @@ -44,7 +44,7 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] [RequireContext(ContextType.Guild)] [RequireUserPermission(GuildPermission.ManageMessages)] - [Priority(0)] + [Priority(1)] public async Task Remind(ITextChannel channel, string timeStr, [Remainder] string message) { var perms = ((IGuildUser)Context.User).GetPermissions((ITextChannel)channel); diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 53288c5c..e6dc2d5c 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -363,10 +363,13 @@ namespace NadekoBot public async Task RunAndBlockAsync(params string[] args) { await RunAsync(args).ConfigureAwait(false); + StartSendingData(); if (ShardCoord != null) await ShardCoord.RunAndBlockAsync(); else + { await Task.Delay(-1).ConfigureAwait(false); + } } private void TerribleElevatedPermissionCheck() diff --git a/src/NadekoBot/Services/Administration/SelfService.cs b/src/NadekoBot/Services/Administration/SelfService.cs index 0c5b6e48..0a288a0b 100644 --- a/src/NadekoBot/Services/Administration/SelfService.cs +++ b/src/NadekoBot/Services/Administration/SelfService.cs @@ -72,39 +72,39 @@ namespace NadekoBot.Services.Administration }); } - private void LoadOwnerChannels() - { - var hs = new HashSet(_creds.OwnerIds); - var channels = new Dictionary>(); + //private void LoadOwnerChannels() + //{ + // var hs = new HashSet(_creds.OwnerIds); + // var channels = new Dictionary>(); - if (hs.Count > 0) - { - foreach (var g in _client.Guilds) - { - if (hs.Count == 0) - break; + // if (hs.Count > 0) + // { + // foreach (var g in _client.Guilds) + // { + // if (hs.Count == 0) + // break; - foreach (var u in g.Users) - { - if (hs.Remove(u.Id)) - { - channels.Add(u.Id, new AsyncLazy(async () => await u.CreateDMChannelAsync())); - if (hs.Count == 0) - break; - } - } - } - } + // foreach (var u in g.Users) + // { + // if (hs.Remove(u.Id)) + // { + // channels.Add(u.Id, new AsyncLazy(async () => await u.CreateDMChannelAsync())); + // if (hs.Count == 0) + // break; + // } + // } + // } + // } - ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key)) - .Select(x => x.Value) - .ToImmutableArray(); + // ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key)) + // .Select(x => x.Value) + // .ToImmutableArray(); - if (!ownerChannels.Any()) - _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); - else - _log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels."); - } + // if (!ownerChannels.Any()) + // _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); + // else + // _log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels."); + //} // forwards dms public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg) diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs index 9f848389..4ed8247f 100644 --- a/src/NadekoBot/ShardsCoordinator.cs +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -78,7 +78,10 @@ namespace NadekoBot .Where(x => x != null) .GroupBy(x => x.ConnectionState) .Select(x => x.Count() + " " + x.Key)); - _log.Info(string.Join("\n", Statuses.Select(x => $"Shard {x.ShardId} is in {x.ConnectionState.ToString()} state with {x.Guilds} servers")) + "\n" + groupStr); + _log.Info(string.Join("\n", Statuses + .ToArray() + .Where(x => x != null) + .Select(x => $"Shard {x.ShardId} is in {x.ConnectionState.ToString()} state with {x.Guilds} servers")) + "\n" + groupStr); break; default: break; From bed3001ce1b15cbbdc8c83dc61c8102e6d9050ea Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 22 Jun 2017 22:16:58 +0200 Subject: [PATCH 15/26] Database should be faster, disabled unit converter temporarily --- .../Utility/Commands/UnitConversion.cs | 180 +++++++++--------- src/NadekoBot/NadekoBot.cs | 4 +- src/NadekoBot/Services/DbService.cs | 11 ++ src/NadekoBot/Services/Impl/BotCredentials.cs | 2 +- 4 files changed, 104 insertions(+), 93 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs index 9b9c121c..603093c4 100644 --- a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs +++ b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs @@ -1,94 +1,94 @@ -using Discord; -using Discord.Commands; -using NadekoBot.Attributes; -using NadekoBot.Extensions; -using NadekoBot.Services.Utility; -using System; -using System.Linq; -using System.Threading.Tasks; +//using Discord; +//using Discord.Commands; +//using NadekoBot.Attributes; +//using NadekoBot.Extensions; +//using NadekoBot.Services.Utility; +//using System; +//using System.Linq; +//using System.Threading.Tasks; -namespace NadekoBot.Modules.Utility -{ - public partial class Utility - { - [Group] - public class UnitConverterCommands : NadekoSubmodule - { - private readonly ConverterService _service; +//namespace NadekoBot.Modules.Utility +//{ +// public partial class Utility +// { +// [Group] +// public class UnitConverterCommands : NadekoSubmodule +// { +// private readonly ConverterService _service; - public UnitConverterCommands(ConverterService service) - { - _service = service; - } +// public UnitConverterCommands(ConverterService service) +// { +// _service = service; +// } - [NadekoCommand, Usage, Description, Aliases] - public async Task ConvertList() - { - var res = _service.Units.GroupBy(x => x.UnitType) - .Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist")) - .WithColor(NadekoBot.OkColor), - (embed, g) => embed.AddField(efb => - efb.WithName(g.Key.ToTitleCase()) - .WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault()) - .OrderBy(x => x))))); - await Context.Channel.EmbedAsync(res); - } - [NadekoCommand, Usage, Description, Aliases] - public async Task Convert(string origin, string target, decimal value) - { - var originUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(origin.ToLowerInvariant())); - var targetUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant())); - if (originUnit == null || targetUnit == null) - { - await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false); - return; - } - if (originUnit.UnitType != targetUnit.UnitType) - { - await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false); - return; - } - decimal res; - if (originUnit.Triggers == targetUnit.Triggers) res = value; - else if (originUnit.UnitType == "temperature") - { - //don't really care too much about efficiency, so just convert to Kelvin, then to target - switch (originUnit.Triggers.First().ToUpperInvariant()) - { - case "C": - res = value + 273.15m; //celcius! - break; - case "F": - res = (value + 459.67m) * (5m / 9m); - break; - default: - res = value; - break; - } - //from Kelvin to target - switch (targetUnit.Triggers.First().ToUpperInvariant()) - { - case "C": - res = res - 273.15m; //celcius! - break; - case "F": - res = res * (9m / 5m) - 459.67m; - break; - } - } - else - { - if (originUnit.UnitType == "currency") - { - res = (value * targetUnit.Modifier) / originUnit.Modifier; - } - else - res = (value * originUnit.Modifier) / targetUnit.Modifier; - } - res = Math.Round(res, 4); +// [NadekoCommand, Usage, Description, Aliases] +// public async Task ConvertList() +// { +// var res = _service.Units.GroupBy(x => x.UnitType) +// .Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist")) +// .WithColor(NadekoBot.OkColor), +// (embed, g) => embed.AddField(efb => +// efb.WithName(g.Key.ToTitleCase()) +// .WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault()) +// .OrderBy(x => x))))); +// await Context.Channel.EmbedAsync(res); +// } +// [NadekoCommand, Usage, Description, Aliases] +// public async Task Convert(string origin, string target, decimal value) +// { +// var originUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(origin.ToLowerInvariant())); +// var targetUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant())); +// if (originUnit == null || targetUnit == null) +// { +// await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false); +// return; +// } +// if (originUnit.UnitType != targetUnit.UnitType) +// { +// await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false); +// return; +// } +// decimal res; +// if (originUnit.Triggers == targetUnit.Triggers) res = value; +// else if (originUnit.UnitType == "temperature") +// { +// //don't really care too much about efficiency, so just convert to Kelvin, then to target +// switch (originUnit.Triggers.First().ToUpperInvariant()) +// { +// case "C": +// res = value + 273.15m; //celcius! +// break; +// case "F": +// res = (value + 459.67m) * (5m / 9m); +// break; +// default: +// res = value; +// break; +// } +// //from Kelvin to target +// switch (targetUnit.Triggers.First().ToUpperInvariant()) +// { +// case "C": +// res = res - 273.15m; //celcius! +// break; +// case "F": +// res = res * (9m / 5m) - 459.67m; +// break; +// } +// } +// else +// { +// if (originUnit.UnitType == "currency") +// { +// res = (value * targetUnit.Modifier) / originUnit.Modifier; +// } +// else +// res = (value * originUnit.Modifier) / targetUnit.Modifier; +// } +// res = Math.Round(res, 4); - await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); - } - } - } -} \ No newline at end of file +// await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); +// } +// } +// } +//} \ No newline at end of file diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index e6dc2d5c..8f6e926b 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -159,7 +159,7 @@ namespace NadekoBot #region utility var remindService = new RemindService(Client, BotConfig, Db, startingGuildIdList); var repeaterService = new MessageRepeaterService(this, Client, AllGuildConfigs); - var converterService = new ConverterService(Db); + //var converterService = new ConverterService(Db); var commandMapService = new CommandMapService(AllGuildConfigs); var patreonRewardsService = new PatreonRewardsService(Credentials, Db, Currency); var verboseErrorsService = new VerboseErrorsService(AllGuildConfigs, Db, CommandHandler, helpService); @@ -230,7 +230,7 @@ namespace NadekoBot .Add(commandMapService) .Add(remindService) .Add(repeaterService) - .Add(converterService) + //.Add(converterService) .Add(verboseErrorsService) .Add(patreonRewardsService) .Add(pruneService) diff --git a/src/NadekoBot/Services/DbService.cs b/src/NadekoBot/Services/DbService.cs index c8fab899..6e9532ca 100644 --- a/src/NadekoBot/Services/DbService.cs +++ b/src/NadekoBot/Services/DbService.cs @@ -36,6 +36,17 @@ namespace NadekoBot.Services context.Database.Migrate(); context.EnsureSeedData(); + //set important sqlite stuffs + var conn = context.Database.GetDbConnection(); + conn.Open(); + + context.Database.ExecuteSqlCommand("PRAGMA journal_mode=WAL"); + using (var com = conn.CreateCommand()) + { + com.CommandText = "PRAGMA journal_mode=WAL; PRAGMA synchronous=OFF"; + com.ExecuteNonQuery(); + } + return context; } diff --git a/src/NadekoBot/Services/Impl/BotCredentials.cs b/src/NadekoBot/Services/Impl/BotCredentials.cs index 3517a298..b54bed23 100644 --- a/src/NadekoBot/Services/Impl/BotCredentials.cs +++ b/src/NadekoBot/Services/Impl/BotCredentials.cs @@ -89,7 +89,7 @@ namespace NadekoBot.Services.Impl ? "sqlite" : dbSection["Type"], string.IsNullOrWhiteSpace(dbSection["ConnectionString"]) - ? "Filename=./data/NadekoBot.db" + ? "Filename=./data/NadekoBot.db" : dbSection["ConnectionString"]); } catch (Exception ex) From 741538a982a635e799ebc2b8475e16589ebcdcb0 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Thu, 22 Jun 2017 23:59:54 +0200 Subject: [PATCH 16/26] Slightly faster startup and database access. Shard 0 will now report total guild count --- .../Utility/Commands/UnitConversion.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 14 +- src/NadekoBot/NadekoBot.cs | 296 +++++++++--------- .../Services/Administration/SelfService.cs | 8 +- .../ClashOfClans/ClashOfClansService.cs | 32 +- .../CustomReactions/CustomReactionsService.cs | 14 +- .../Repositories/IClashOfClansRepository.cs | 2 +- .../Impl/ClashOfClansRepository.cs | 6 +- src/NadekoBot/Services/IStatsService.cs | 1 + src/NadekoBot/Services/Impl/StatsService.cs | 58 ++-- .../Permissions/PermissionsService.cs | 41 +-- .../Searches/StreamNotificationService.cs | 4 +- .../Services/Utility/RemindService.cs | 11 +- src/NadekoBot/ShardsCoordinator.cs | 4 + 14 files changed, 252 insertions(+), 241 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs index 603093c4..f325c402 100644 --- a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs +++ b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs @@ -6,7 +6,7 @@ //using System; //using System.Linq; //using System.Threading.Tasks; - +////todo Rewrite //namespace NadekoBot.Modules.Utility //{ // public partial class Utility diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 51f24efc..3ae25163 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -319,11 +319,7 @@ namespace NadekoBot.Modules.Utility [NadekoCommand, Usage, Description, Aliases] public async Task Stats() - { - //var shardId = Context.Guild != null - // ? _client.GetShardIdFor(Context.Guild) - // : 0; - + { await Context.Channel.EmbedAsync( new EmbedBuilder().WithOkColor() .WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}") @@ -339,13 +335,7 @@ namespace NadekoBot.Modules.Utility .AddField(efb => efb.WithName(GetText("uptime")).WithValue(_stats.GetUptimeString("\n")).WithIsInline(true)) .AddField(efb => efb.WithName(GetText("presence")).WithValue( GetText("presence_txt", - _client.Guilds.Count, _stats.TextChannels, _stats.VoiceChannels)).WithIsInline(true)) -#if !GLOBAL_NADEKO - //.WithFooter(efb => efb.WithText(GetText("stats_songs", - // _music.MusicPlayers.Count(mp => mp.Value.CurrentSong != null), - // _music.MusicPlayers.Sum(mp => mp.Value.Playlist.Count)))) -#endif - ); + _stats.GuildCount, _stats.TextChannels, _stats.VoiceChannels)).WithIsInline(true))); } [NadekoCommand, Usage, Description, Aliases] diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 8f6e926b..9025a0a3 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -139,169 +139,179 @@ namespace NadekoBot private void AddServices() { var startingGuildIdList = Client.Guilds.Select(x => (long)x.Id).ToList(); + + //this unit of work will be used for initialization of all modules too, to prevent multiple queries from running using (var uow = Db.UnitOfWork) { AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs(startingGuildIdList).ToImmutableArray(); + + Localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db); + Strings = new NadekoStrings(Localization); + CommandHandler = new CommandHandler(Client, Db, BotConfig, AllGuildConfigs, CommandService, Credentials, this); + Stats = new StatsService(Client, CommandHandler, Credentials, ShardCoord); + + var soundcloudApiService = new SoundCloudApiService(Credentials); + + #region help + var helpService = new HelpService(BotConfig, CommandHandler, Strings); + #endregion + + //module services + //todo 90 - autodiscover, DI, and add instead of manual like this + #region utility + var remindService = new RemindService(Client, BotConfig, Db, startingGuildIdList, uow); + var repeaterService = new MessageRepeaterService(this, Client, AllGuildConfigs); + //var converterService = new ConverterService(Db); + var commandMapService = new CommandMapService(AllGuildConfigs); + var patreonRewardsService = new PatreonRewardsService(Credentials, Db, Currency); + var verboseErrorsService = new VerboseErrorsService(AllGuildConfigs, Db, CommandHandler, helpService); + var pruneService = new PruneService(); + #endregion + + #region permissions + var permissionsService = new PermissionService(Client, Db, BotConfig, CommandHandler); + var blacklistService = new BlacklistService(BotConfig); + var cmdcdsService = new CmdCdService(AllGuildConfigs); + var filterService = new FilterService(Client, AllGuildConfigs); + var globalPermsService = new GlobalPermissionService(BotConfig); + #endregion + + #region Searches + var searchesService = new SearchesService(Client, GoogleApi, Db); + var streamNotificationService = new StreamNotificationService(Db, Client, Strings); + var animeSearchService = new AnimeSearchService(); + #endregion + + var clashService = new ClashOfClansService(Client, Db, Localization, Strings, uow, startingGuildIdList); + var musicService = new MusicService(GoogleApi, Strings, Localization, Db, soundcloudApiService, Credentials, AllGuildConfigs); + var crService = new CustomReactionsService(permissionsService, Db, Client, CommandHandler, BotConfig, uow); + + #region Games + var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, Strings, Images, CommandHandler); + var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs, CommandHandler); + var pollService = new PollService(Client, Strings); + #endregion + + #region administration + var administrationService = new AdministrationService(AllGuildConfigs, CommandHandler); + var greetSettingsService = new GreetSettingsService(Client, AllGuildConfigs, Db); + var selfService = new SelfService(Client, this, CommandHandler, Db, BotConfig, Localization, Strings, Credentials); + var vcRoleService = new VcRoleService(Client, AllGuildConfigs, Db); + var vPlusTService = new VplusTService(Client, AllGuildConfigs, Strings, Db); + var muteService = new MuteService(Client, AllGuildConfigs, Db); + var ratelimitService = new SlowmodeService(Client, AllGuildConfigs); + var protectionService = new ProtectionService(Client, AllGuildConfigs, muteService); + var playingRotateService = new PlayingRotateService(Client, BotConfig, musicService); + var gameVcService = new GameVoiceChannelService(Client, Db, AllGuildConfigs); + var autoAssignRoleService = new AutoAssignRoleService(Client, AllGuildConfigs); + var logCommandService = new LogCommandService(Client, Strings, AllGuildConfigs, Db, muteService, protectionService); + var guildTimezoneService = new GuildTimezoneService(AllGuildConfigs, Db); + #endregion + + #region pokemon + var pokemonService = new PokemonService(); + #endregion + + + + //initialize Services + Services = new NServiceProvider.ServiceProviderBuilder() + .Add(Localization) + .Add(Stats) + .Add(Images) + .Add(GoogleApi) + .Add(Stats) + .Add(Credentials) + .Add(CommandService) + .Add(Strings) + .Add(Client) + .Add(BotConfig) + .Add(Currency) + .Add(CommandHandler) + .Add(Db) + //modules + .Add(commandMapService) + .Add(remindService) + .Add(repeaterService) + //.Add(converterService) + .Add(verboseErrorsService) + .Add(patreonRewardsService) + .Add(pruneService) + .Add(searchesService) + .Add(streamNotificationService) + .Add(animeSearchService) + .Add(clashService) + .Add(musicService) + .Add(greetSettingsService) + .Add(crService) + .Add(helpService) + .Add(gamesService) + .Add(chatterBotService) + .Add(pollService) + .Add(administrationService) + .Add(selfService) + .Add(vcRoleService) + .Add(vPlusTService) + .Add(muteService) + .Add(ratelimitService) + .Add(playingRotateService) + .Add(gameVcService) + .Add(autoAssignRoleService) + .Add(protectionService) + .Add(logCommandService) + .Add(guildTimezoneService) + .Add(permissionsService) + .Add(blacklistService) + .Add(cmdcdsService) + .Add(filterService) + .Add(globalPermsService) + .Add(pokemonService) + .Add(this) + .Build(); + + + CommandHandler.AddServices(Services); + + //setup typereaders + CommandService.AddTypeReader(new PermissionActionTypeReader()); + CommandService.AddTypeReader(new CommandTypeReader(CommandService, CommandHandler)); + CommandService.AddTypeReader(new CommandOrCrTypeReader(crService, CommandService, CommandHandler)); + CommandService.AddTypeReader(new ModuleTypeReader(CommandService)); + CommandService.AddTypeReader(new ModuleOrCrTypeReader(CommandService)); + CommandService.AddTypeReader(new GuildTypeReader(Client)); + CommandService.AddTypeReader(new GuildDateTimeTypeReader(guildTimezoneService)); + } - Localization = new Localization(BotConfig.Locale, AllGuildConfigs.ToDictionary(x => x.GuildId, x => x.Locale), Db); - Strings = new NadekoStrings(Localization); - CommandHandler = new CommandHandler(Client, Db, BotConfig, AllGuildConfigs, CommandService, Credentials, this); - Stats = new StatsService(Client, CommandHandler, Credentials); - - var soundcloudApiService = new SoundCloudApiService(Credentials); - - #region help - var helpService = new HelpService(BotConfig, CommandHandler, Strings); - #endregion - - //module services - //todo 90 - autodiscover, DI, and add instead of manual like this - #region utility - var remindService = new RemindService(Client, BotConfig, Db, startingGuildIdList); - var repeaterService = new MessageRepeaterService(this, Client, AllGuildConfigs); - //var converterService = new ConverterService(Db); - var commandMapService = new CommandMapService(AllGuildConfigs); - var patreonRewardsService = new PatreonRewardsService(Credentials, Db, Currency); - var verboseErrorsService = new VerboseErrorsService(AllGuildConfigs, Db, CommandHandler, helpService); - var pruneService = new PruneService(); - #endregion - - #region permissions - var permissionsService = new PermissionService(Client, Db, BotConfig, CommandHandler); - var blacklistService = new BlacklistService(BotConfig); - var cmdcdsService = new CmdCdService(AllGuildConfigs); - var filterService = new FilterService(Client, AllGuildConfigs); - var globalPermsService = new GlobalPermissionService(BotConfig); - #endregion - - #region Searches - var searchesService = new SearchesService(Client, GoogleApi, Db); - var streamNotificationService = new StreamNotificationService(Db, Client, Strings); - var animeSearchService = new AnimeSearchService(); - #endregion - - var clashService = new ClashOfClansService(Client, Db, Localization, Strings); - var musicService = new MusicService(GoogleApi, Strings, Localization, Db, soundcloudApiService, Credentials, AllGuildConfigs); - var crService = new CustomReactionsService(permissionsService, Db, Client, CommandHandler, BotConfig); - - #region Games - var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, Strings, Images, CommandHandler); - var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs, CommandHandler); - var pollService = new PollService(Client, Strings); - #endregion - - #region administration - var administrationService = new AdministrationService(AllGuildConfigs, CommandHandler); - var greetSettingsService = new GreetSettingsService(Client, AllGuildConfigs, Db); - var selfService = new SelfService(Client, this, CommandHandler, Db, BotConfig, Localization, Strings, Credentials); - var vcRoleService = new VcRoleService(Client, AllGuildConfigs, Db); - var vPlusTService = new VplusTService(Client, AllGuildConfigs, Strings, Db); - var muteService = new MuteService(Client, AllGuildConfigs, Db); - var ratelimitService = new SlowmodeService(Client, AllGuildConfigs); - var protectionService = new ProtectionService(Client, AllGuildConfigs, muteService); - var playingRotateService = new PlayingRotateService(Client, BotConfig, musicService); - var gameVcService = new GameVoiceChannelService(Client, Db, AllGuildConfigs); - var autoAssignRoleService = new AutoAssignRoleService(Client, AllGuildConfigs); - var logCommandService = new LogCommandService(Client, Strings, AllGuildConfigs, Db, muteService, protectionService); - var guildTimezoneService = new GuildTimezoneService(AllGuildConfigs, Db); - #endregion - - #region pokemon - var pokemonService = new PokemonService(); - #endregion - - - //initialize Services - Services = new NServiceProvider.ServiceProviderBuilder() - .Add(Localization) - .Add(Stats) - .Add(Images) - .Add(GoogleApi) - .Add(Stats) - .Add(Credentials) - .Add(CommandService) - .Add(Strings) - .Add(Client) - .Add(BotConfig) - .Add(Currency) - .Add(CommandHandler) - .Add(Db) - //modules - .Add(commandMapService) - .Add(remindService) - .Add(repeaterService) - //.Add(converterService) - .Add(verboseErrorsService) - .Add(patreonRewardsService) - .Add(pruneService) - .Add(searchesService) - .Add(streamNotificationService) - .Add(animeSearchService) - .Add(clashService) - .Add(musicService) - .Add(greetSettingsService) - .Add(crService) - .Add(helpService) - .Add(gamesService) - .Add(chatterBotService) - .Add(pollService) - .Add(administrationService) - .Add(selfService) - .Add(vcRoleService) - .Add(vPlusTService) - .Add(muteService) - .Add(ratelimitService) - .Add(playingRotateService) - .Add(gameVcService) - .Add(autoAssignRoleService) - .Add(protectionService) - .Add(logCommandService) - .Add(guildTimezoneService) - .Add(permissionsService) - .Add(blacklistService) - .Add(cmdcdsService) - .Add(filterService) - .Add(globalPermsService) - .Add(pokemonService) - .Add(this) - .Build(); - - CommandHandler.AddServices(Services); - - //setup typereaders - CommandService.AddTypeReader(new PermissionActionTypeReader()); - CommandService.AddTypeReader(new CommandTypeReader(CommandService, CommandHandler)); - CommandService.AddTypeReader(new CommandOrCrTypeReader(crService, CommandService, CommandHandler)); - CommandService.AddTypeReader(new ModuleTypeReader(CommandService)); - CommandService.AddTypeReader(new ModuleOrCrTypeReader(CommandService)); - CommandService.AddTypeReader(new GuildTypeReader(Client)); - CommandService.AddTypeReader(new GuildDateTimeTypeReader(guildTimezoneService)); } - private Task LoginAsync(string token) + private async Task LoginAsync(string token) { + var clientReady = new TaskCompletionSource(); + + Task SetClientReady() + { + clientReady.TrySetResult(true); + return Task.CompletedTask; + } + //connect try { sem.WaitOne(); } catch (AbandonedMutexException) { } + _log.Info("Shard {0} logging in ...", ShardId); + try { Client.LoginAsync(TokenType.Bot, token).GetAwaiter().GetResult(); Client.StartAsync().GetAwaiter().GetResult(); - while (Client.ConnectionState != ConnectionState.Connected) - Task.Delay(100).GetAwaiter().GetResult(); + Client.Ready += SetClientReady; + await clientReady.Task.ConfigureAwait(false); + Client.Ready -= SetClientReady; } finally { _log.Info("Shard {0} logged in.", ShardId); sem.Release(); } - return Task.CompletedTask; - //_log.Info("Waiting for all shards to connect..."); - //while (!Client.Shards.All(x => x.ConnectionState == ConnectionState.Connected)) - //{ - // _log.Info("Connecting... {0}/{1}", Client.Shards.Count(x => x.ConnectionState == ConnectionState.Connected), Client.Shards.Count); - // await Task.Delay(1000).ConfigureAwait(false); - //} } public async Task RunAsync(params string[] args) diff --git a/src/NadekoBot/Services/Administration/SelfService.cs b/src/NadekoBot/Services/Administration/SelfService.cs index 0a288a0b..336f9970 100644 --- a/src/NadekoBot/Services/Administration/SelfService.cs +++ b/src/NadekoBot/Services/Administration/SelfService.cs @@ -39,12 +39,8 @@ namespace NadekoBot.Services.Administration _client = client; _creds = creds; - using (var uow = _db.UnitOfWork) - { - var config = uow.BotConfig.GetOrCreate(); - ForwardDMs = config.ForwardMessages; - ForwardDMsToAllOwners = config.ForwardToAllOwners; - } + ForwardDMs = bc.ForwardMessages; + ForwardDMsToAllOwners = bc.ForwardToAllOwners; var _ = Task.Run(async () => { diff --git a/src/NadekoBot/Services/ClashOfClans/ClashOfClansService.cs b/src/NadekoBot/Services/ClashOfClans/ClashOfClansService.cs index 042afa1b..dcdd6376 100644 --- a/src/NadekoBot/Services/ClashOfClans/ClashOfClansService.cs +++ b/src/NadekoBot/Services/ClashOfClans/ClashOfClansService.cs @@ -1,6 +1,7 @@ using Discord; using Discord.WebSocket; using NadekoBot.Extensions; +using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using System; using System.Collections.Concurrent; @@ -25,28 +26,27 @@ namespace NadekoBot.Services.ClashOfClans public ConcurrentDictionary> ClashWars { get; set; } - public ClashOfClansService(DiscordSocketClient client, DbService db, ILocalization localization, NadekoStrings strings) + public ClashOfClansService(DiscordSocketClient client, DbService db, + ILocalization localization, NadekoStrings strings, IUnitOfWork uow, + List guilds) { _client = client; _db = db; _localization = localization; _strings = strings; - using (var uow = _db.UnitOfWork) - { - ClashWars = new ConcurrentDictionary>( - uow.ClashOfClans - .GetAllWars() - .Select(cw => - { - cw.Channel = _client.GetGuild(cw.GuildId)? - .GetTextChannel(cw.ChannelId); - return cw; - }) - .Where(cw => cw.Channel != null) - .GroupBy(cw => cw.GuildId) - .ToDictionary(g => g.Key, g => g.ToList())); - } + ClashWars = new ConcurrentDictionary>( + uow.ClashOfClans + .GetAllWars(guilds) + .Select(cw => + { + cw.Channel = _client.GetGuild(cw.GuildId)? + .GetTextChannel(cw.ChannelId); + return cw; + }) + .Where(cw => cw.Channel != null) + .GroupBy(cw => cw.GuildId) + .ToDictionary(g => g.Key, g => g.ToList())); checkWarTimer = new Timer(async _ => { diff --git a/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs b/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs index bb7fb8d9..ecf0dede 100644 --- a/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs +++ b/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs @@ -10,6 +10,7 @@ using System; using System.Threading.Tasks; using NadekoBot.Services.Permissions; using NadekoBot.Extensions; +using NadekoBot.Services.Database; namespace NadekoBot.Services.CustomReactions { @@ -28,7 +29,7 @@ namespace NadekoBot.Services.CustomReactions private readonly BotConfig _bc; public CustomReactionsService(PermissionService perms, DbService db, - DiscordSocketClient client, CommandHandler cmd, BotConfig bc) + DiscordSocketClient client, CommandHandler cmd, BotConfig bc, IUnitOfWork uow) { _log = LogManager.GetCurrentClassLogger(); _db = db; @@ -36,13 +37,10 @@ namespace NadekoBot.Services.CustomReactions _perms = perms; _cmd = cmd; _bc = bc; - - using (var uow = _db.UnitOfWork) - { - var items = uow.CustomReactions.GetAll(); - GuildReactions = new ConcurrentDictionary(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray())); - GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray(); - } + + var items = uow.CustomReactions.GetAll(); + GuildReactions = new ConcurrentDictionary(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray())); + GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray(); } public void ClearStats() => ReactionStats.Clear(); diff --git a/src/NadekoBot/Services/Database/Repositories/IClashOfClansRepository.cs b/src/NadekoBot/Services/Database/Repositories/IClashOfClansRepository.cs index 756e9789..14edcea8 100644 --- a/src/NadekoBot/Services/Database/Repositories/IClashOfClansRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/IClashOfClansRepository.cs @@ -5,6 +5,6 @@ namespace NadekoBot.Services.Database.Repositories { public interface IClashOfClansRepository : IRepository { - IEnumerable GetAllWars(); + IEnumerable GetAllWars(List guilds); } } diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/ClashOfClansRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/ClashOfClansRepository.cs index 54a391fa..828c4bce 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/ClashOfClansRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/ClashOfClansRepository.cs @@ -11,9 +11,11 @@ namespace NadekoBot.Services.Database.Repositories.Impl { } - public IEnumerable GetAllWars() + public IEnumerable GetAllWars(List guilds) { - var toReturn = _set.Include(cw => cw.Bases) + var toReturn = _set + .Where(cw => guilds.Contains((long)cw.GuildId)) + .Include(cw => cw.Bases) .ToList(); toReturn.ForEach(cw => cw.Bases = cw.Bases.Where(w => w.SequenceNumber != null).OrderBy(w => w.SequenceNumber).ToList()); return toReturn; diff --git a/src/NadekoBot/Services/IStatsService.cs b/src/NadekoBot/Services/IStatsService.cs index a7735fc8..d187c413 100644 --- a/src/NadekoBot/Services/IStatsService.cs +++ b/src/NadekoBot/Services/IStatsService.cs @@ -13,6 +13,7 @@ namespace NadekoBot.Services double MessagesPerSecond { get; } long TextChannels { get; } long VoiceChannels { get; } + int GuildCount { get; } TimeSpan GetUptime(); string GetUptimeString(string separator = ", "); diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 5d93196d..8cce6936 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -35,11 +35,16 @@ namespace NadekoBot.Services.Impl public long CommandsRan => Interlocked.Read(ref _commandsRan); private readonly Timer _carbonitexTimer; + private readonly ShardsCoordinator _sc; - public StatsService(DiscordSocketClient client, CommandHandler cmdHandler, IBotCredentials creds) + public int GuildCount => + _sc?.GuildCount ?? _client.Guilds.Count(); + + public StatsService(DiscordSocketClient client, CommandHandler cmdHandler, IBotCredentials creds, ShardsCoordinator sc) { _client = client; _creds = creds; + _sc = sc; _started = DateTime.UtcNow; _client.MessageReceived += _ => Task.FromResult(Interlocked.Increment(ref _messageCounter)); @@ -122,31 +127,34 @@ namespace NadekoBot.Services.Impl }; //todo carbonitex update - //_carbonitexTimer = new Timer(async (state) => - //{ - // if (string.IsNullOrWhiteSpace(_creds.CarbonKey)) - // return; - // try - // { - // using (var http = new HttpClient()) - // { - // using (var content = new FormUrlEncodedContent( - // new Dictionary { - // { "servercount", _client.Guilds.Count.ToString() }, - // { "key", _creds.CarbonKey }})) - // { - // content.Headers.Clear(); - // content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); + if (sc != null) + { + _carbonitexTimer = new Timer(async (state) => + { + if (string.IsNullOrWhiteSpace(_creds.CarbonKey)) + return; + try + { + using (var http = new HttpClient()) + { + using (var content = new FormUrlEncodedContent( + new Dictionary { + { "servercount", sc.GuildCount.ToString() }, + { "key", _creds.CarbonKey }})) + { + content.Headers.Clear(); + content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); - // await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false); - // } - // } - // } - // catch - // { - // // ignored - // } - //}, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); + await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false); + } + } + } + catch + { + // ignored + } + }, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); + } } public void Initialize() diff --git a/src/NadekoBot/Services/Permissions/PermissionsService.cs b/src/NadekoBot/Services/Permissions/PermissionsService.cs index 7ca39a03..00794d2d 100644 --- a/src/NadekoBot/Services/Permissions/PermissionsService.cs +++ b/src/NadekoBot/Services/Permissions/PermissionsService.cs @@ -11,6 +11,7 @@ using System.Threading.Tasks; using Discord; using Discord.WebSocket; using NadekoBot.Extensions; +using NadekoBot.Services; namespace NadekoBot.Services.Permissions { @@ -31,24 +32,21 @@ namespace NadekoBot.Services.Permissions _cmd = cmd; var sw = Stopwatch.StartNew(); - TryMigratePermissions(bc); + if (client.ShardId == 0) + TryMigratePermissions(bc); - client.Ready += delegate + using (var uow = _db.UnitOfWork) { - using (var uow = _db.UnitOfWork) + foreach (var x in uow.GuildConfigs.Permissionsv2ForAll(client.Guilds.ToArray().Select(x => (long)x.Id).ToList())) { - foreach (var x in uow.GuildConfigs.Permissionsv2ForAll(client.Guilds.Select(x => (long)x.Id).ToList())) + Cache.TryAdd(x.GuildId, new PermissionCache() { - Cache.TryAdd(x.GuildId, new PermissionCache() - { - Verbose = x.VerbosePermissions, - PermRole = x.PermissionRole, - Permissions = new PermissionsCollection(x.Permissions) - }); - } + Verbose = x.VerbosePermissions, + PermRole = x.PermissionRole, + Permissions = new PermissionsCollection(x.Permissions) + }); } - return Task.CompletedTask; - }; + } sw.Stop(); _log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s"); @@ -74,10 +72,9 @@ namespace NadekoBot.Services.Permissions private void TryMigratePermissions(BotConfig bc) { var log = LogManager.GetCurrentClassLogger(); - using (var uow = _db.UnitOfWork) + if (bc.PermissionVersion <= 1) { - var _bc = uow.BotConfig.GetOrCreate(); - if (_bc.PermissionVersion <= 1) + using (var uow = _db.UnitOfWork) { log.Info("Permission version is 1, upgrading to 2."); var oldCache = new ConcurrentDictionary(uow.GuildConfigs @@ -132,9 +129,13 @@ namespace NadekoBot.Services.Permissions log.Info("Permission migration to v2 is done."); } - _bc.PermissionVersion = 2; + bc.PermissionVersion = 2; + uow.Complete(); } - if (_bc.PermissionVersion <= 2) + } + if (bc.PermissionVersion <= 2) + { + using (var uow = _db.UnitOfWork) { var oldPrefixes = new[] { ".", ";", "!!", "!m", "!", "+", "-", "$", ">" }; uow._context.Database.ExecuteSqlCommand( @@ -150,9 +151,9 @@ WHERE secondaryTargetName LIKE '.%' OR secondaryTargetName LIKE '>%' OR secondaryTargetName LIKE '-%' OR secondaryTargetName LIKE '!%';"); - _bc.PermissionVersion = 3; + bc.PermissionVersion = 3; + uow.Complete(); } - uow.Complete(); } } diff --git a/src/NadekoBot/Services/Searches/StreamNotificationService.cs b/src/NadekoBot/Services/Searches/StreamNotificationService.cs index a5846362..c077e4e1 100644 --- a/src/NadekoBot/Services/Searches/StreamNotificationService.cs +++ b/src/NadekoBot/Services/Searches/StreamNotificationService.cs @@ -1,6 +1,8 @@ using Discord; using Discord.WebSocket; using NadekoBot.Extensions; +using NadekoBot.Services; +using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using Newtonsoft.Json; using System; @@ -73,7 +75,7 @@ namespace NadekoBot.Services.Searches })); firstStreamNotifPass = false; - }, null, TimeSpan.Zero, TimeSpan.FromSeconds(60)); + }, null, TimeSpan.FromSeconds(60), TimeSpan.FromSeconds(60)); } public async Task GetStreamStatus(FollowedStream stream, bool checkCache = true) diff --git a/src/NadekoBot/Services/Utility/RemindService.cs b/src/NadekoBot/Services/Utility/RemindService.cs index 16d6d451..8629712d 100644 --- a/src/NadekoBot/Services/Utility/RemindService.cs +++ b/src/NadekoBot/Services/Utility/RemindService.cs @@ -1,6 +1,7 @@ using Discord; using Discord.WebSocket; using NadekoBot.Extensions; +using NadekoBot.Services.Database; using NadekoBot.Services.Database.Models; using NLog; using System; @@ -33,7 +34,8 @@ namespace NadekoBot.Services.Utility private readonly DiscordSocketClient _client; private readonly DbService _db; - public RemindService(DiscordSocketClient client, BotConfig config, DbService db, List guilds) + public RemindService(DiscordSocketClient client, BotConfig config, DbService db, + List guilds, IUnitOfWork uow) { _config = config; _client = client; @@ -42,11 +44,8 @@ namespace NadekoBot.Services.Utility cancelSource = new CancellationTokenSource(); cancelAllToken = cancelSource.Token; - List reminders; - using (var uow = _db.UnitOfWork) - { - reminders = uow.Reminders.GetIncludedReminders(guilds).ToList(); - } + + var reminders = uow.Reminders.GetIncludedReminders(guilds).ToList(); RemindMessageFormat = _config.RemindMessageFormat; foreach (var r in reminders) diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs index 4ed8247f..3fe6da58 100644 --- a/src/NadekoBot/ShardsCoordinator.cs +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -14,6 +14,10 @@ namespace NadekoBot private readonly BotCredentials Credentials; private Process[] ShardProcesses; public ShardComMessage[] Statuses { get; } + public int GuildCount => Statuses.ToArray() + .Where(x => x != null) + .Sum(x => x.Guilds); + private readonly Logger _log; private readonly ShardComServer _comServer; From a8f2ca60c2a349780800cbec87adc52d239ef6df Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 24 Jun 2017 01:41:24 +0200 Subject: [PATCH 17/26] Reenabled converter commands. Improved rewards reload on bots with multiple shards. --- .gitignore | 1 + .../Utility/Commands/UnitConversion.cs | 181 +++++++++--------- src/NadekoBot/NadekoBot.cs | 5 +- src/NadekoBot/NadekoBot.csproj | 1 + src/NadekoBot/Services/Impl/StatsService.cs | 1 - .../Services/Utility/ConverterService.cs | 88 +++++---- .../Services/Utility/PatreonRewardsService.cs | 97 +++++----- 7 files changed, 200 insertions(+), 174 deletions(-) diff --git a/.gitignore b/.gitignore index 0fa1ef5e..5169035d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ #Manually added files +patreon_rewards.json command_errors*.txt src/NadekoBot/Command Errors*.txt diff --git a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs index f325c402..1e7f5d22 100644 --- a/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs +++ b/src/NadekoBot/Modules/Utility/Commands/UnitConversion.cs @@ -1,94 +1,93 @@ -//using Discord; -//using Discord.Commands; -//using NadekoBot.Attributes; -//using NadekoBot.Extensions; -//using NadekoBot.Services.Utility; -//using System; -//using System.Linq; -//using System.Threading.Tasks; -////todo Rewrite -//namespace NadekoBot.Modules.Utility -//{ -// public partial class Utility -// { -// [Group] -// public class UnitConverterCommands : NadekoSubmodule -// { -// private readonly ConverterService _service; +using Discord; +using Discord.Commands; +using NadekoBot.Attributes; +using NadekoBot.Extensions; +using NadekoBot.Services.Utility; +using System; +using System.Linq; +using System.Threading.Tasks; +namespace NadekoBot.Modules.Utility +{ + public partial class Utility + { + [Group] + public class UnitConverterCommands : NadekoSubmodule + { + private readonly ConverterService _service; -// public UnitConverterCommands(ConverterService service) -// { -// _service = service; -// } + public UnitConverterCommands(ConverterService service) + { + _service = service; + } -// [NadekoCommand, Usage, Description, Aliases] -// public async Task ConvertList() -// { -// var res = _service.Units.GroupBy(x => x.UnitType) -// .Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist")) -// .WithColor(NadekoBot.OkColor), -// (embed, g) => embed.AddField(efb => -// efb.WithName(g.Key.ToTitleCase()) -// .WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault()) -// .OrderBy(x => x))))); -// await Context.Channel.EmbedAsync(res); -// } -// [NadekoCommand, Usage, Description, Aliases] -// public async Task Convert(string origin, string target, decimal value) -// { -// var originUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(origin.ToLowerInvariant())); -// var targetUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant())); -// if (originUnit == null || targetUnit == null) -// { -// await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false); -// return; -// } -// if (originUnit.UnitType != targetUnit.UnitType) -// { -// await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false); -// return; -// } -// decimal res; -// if (originUnit.Triggers == targetUnit.Triggers) res = value; -// else if (originUnit.UnitType == "temperature") -// { -// //don't really care too much about efficiency, so just convert to Kelvin, then to target -// switch (originUnit.Triggers.First().ToUpperInvariant()) -// { -// case "C": -// res = value + 273.15m; //celcius! -// break; -// case "F": -// res = (value + 459.67m) * (5m / 9m); -// break; -// default: -// res = value; -// break; -// } -// //from Kelvin to target -// switch (targetUnit.Triggers.First().ToUpperInvariant()) -// { -// case "C": -// res = res - 273.15m; //celcius! -// break; -// case "F": -// res = res * (9m / 5m) - 459.67m; -// break; -// } -// } -// else -// { -// if (originUnit.UnitType == "currency") -// { -// res = (value * targetUnit.Modifier) / originUnit.Modifier; -// } -// else -// res = (value * originUnit.Modifier) / targetUnit.Modifier; -// } -// res = Math.Round(res, 4); + [NadekoCommand, Usage, Description, Aliases] + public async Task ConvertList() + { + var res = _service.Units.GroupBy(x => x.UnitType) + .Aggregate(new EmbedBuilder().WithTitle(GetText("convertlist")) + .WithColor(NadekoBot.OkColor), + (embed, g) => embed.AddField(efb => + efb.WithName(g.Key.ToTitleCase()) + .WithValue(String.Join(", ", g.Select(x => x.Triggers.FirstOrDefault()) + .OrderBy(x => x))))); + await Context.Channel.EmbedAsync(res); + } + [NadekoCommand, Usage, Description, Aliases] + public async Task Convert(string origin, string target, decimal value) + { + var originUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(origin.ToLowerInvariant())); + var targetUnit = _service.Units.Find(x => x.Triggers.Select(y => y.ToLowerInvariant()).Contains(target.ToLowerInvariant())); + if (originUnit == null || targetUnit == null) + { + await ReplyErrorLocalized("convert_not_found", Format.Bold(origin), Format.Bold(target)).ConfigureAwait(false); + return; + } + if (originUnit.UnitType != targetUnit.UnitType) + { + await ReplyErrorLocalized("convert_type_error", Format.Bold(originUnit.Triggers.First()), Format.Bold(targetUnit.Triggers.First())).ConfigureAwait(false); + return; + } + decimal res; + if (originUnit.Triggers == targetUnit.Triggers) res = value; + else if (originUnit.UnitType == "temperature") + { + //don't really care too much about efficiency, so just convert to Kelvin, then to target + switch (originUnit.Triggers.First().ToUpperInvariant()) + { + case "C": + res = value + 273.15m; //celcius! + break; + case "F": + res = (value + 459.67m) * (5m / 9m); + break; + default: + res = value; + break; + } + //from Kelvin to target + switch (targetUnit.Triggers.First().ToUpperInvariant()) + { + case "C": + res = res - 273.15m; //celcius! + break; + case "F": + res = res * (9m / 5m) - 459.67m; + break; + } + } + else + { + if (originUnit.UnitType == "currency") + { + res = (value * targetUnit.Modifier) / originUnit.Modifier; + } + else + res = (value * originUnit.Modifier) / targetUnit.Modifier; + } + res = Math.Round(res, 4); -// await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); -// } -// } -// } -//} \ No newline at end of file + await Context.Channel.SendConfirmAsync(GetText("convert", value, (originUnit.Triggers.First()).SnPl(value.IsInteger() ? (int)value : 2), res, (targetUnit.Triggers.First() + "s").SnPl(res.IsInteger() ? (int)res : 2))); + } + } + } +} \ No newline at end of file diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 9025a0a3..2ee3d1b3 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -290,7 +290,10 @@ namespace NadekoBot Task SetClientReady() { - clientReady.TrySetResult(true); + var _ = Task.Run(() => + { + clientReady.TrySetResult(true); + }); return Task.CompletedTask; } diff --git a/src/NadekoBot/NadekoBot.csproj b/src/NadekoBot/NadekoBot.csproj index 0cc722bc..18ad4911 100644 --- a/src/NadekoBot/NadekoBot.csproj +++ b/src/NadekoBot/NadekoBot.csproj @@ -90,5 +90,6 @@ + diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 8cce6936..64507106 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -126,7 +126,6 @@ namespace NadekoBot.Services.Impl return Task.CompletedTask; }; - //todo carbonitex update if (sc != null) { _carbonitexTimer = new Timer(async (state) => diff --git a/src/NadekoBot/Services/Utility/ConverterService.cs b/src/NadekoBot/Services/Utility/ConverterService.cs index b7388335..1edb470a 100644 --- a/src/NadekoBot/Services/Utility/ConverterService.cs +++ b/src/NadekoBot/Services/Utility/ConverterService.cs @@ -1,4 +1,6 @@ -using NadekoBot.Services.Database.Models; +using Discord.WebSocket; +using NadekoBot.Services; +using NadekoBot.Services.Database.Models; using Newtonsoft.Json; using NLog; using System; @@ -11,27 +13,29 @@ using System.Threading.Tasks; namespace NadekoBot.Services.Utility { - //todo periodically load from the database, update only on shard 0 public class ConverterService { - public List Units { get; set; } = new List(); + public List Units { get; } = new List(); private readonly Logger _log; - private Timer _timer; + private readonly Timer _currencyUpdater; + private readonly Timer _currencyLoader; private readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0); private readonly DbService _db; - public ConverterService(DbService db) + public ConverterService(DiscordSocketClient client, DbService db) { _log = LogManager.GetCurrentClassLogger(); _db = db; try { - var data = JsonConvert.DeserializeObject>(File.ReadAllText("data/units.json")).Select(u => new ConvertUnit() - { - Modifier = u.Modifier, - UnitType = u.UnitType, - InternalTrigger = string.Join("|", u.Triggers) - }).ToArray(); + var data = JsonConvert.DeserializeObject>( + File.ReadAllText("data/units.json")) + .Select(u => new ConvertUnit() + { + Modifier = u.Modifier, + UnitType = u.UnitType, + InternalTrigger = string.Join("|", u.Triggers) + }).ToArray(); using (var uow = _db.UnitOfWork) { @@ -48,10 +52,10 @@ namespace NadekoBot.Services.Utility _log.Warn("Could not load units: " + ex.Message); } - _timer = new Timer(async (obj) => await UpdateCurrency(), null, _updateInterval, _updateInterval); + _currencyUpdater = new Timer(async (shouldLoad) => await UpdateCurrency((bool)shouldLoad), client.ShardId == 0, _updateInterval, _updateInterval); } - public static async Task UpdateCurrencyRates() + private async Task GetCurrencyRates() { using (var http = new HttpClient()) { @@ -60,38 +64,48 @@ namespace NadekoBot.Services.Utility } } - public async Task UpdateCurrency() + private async Task UpdateCurrency(bool shouldLoad) { try { - var currencyRates = await UpdateCurrencyRates(); var unitTypeString = "currency"; - var range = currencyRates.ConversionRates.Select(u => new ConvertUnit() + if (shouldLoad) { - InternalTrigger = u.Key, - Modifier = u.Value, - UnitType = unitTypeString - }).ToArray(); - var baseType = new ConvertUnit() - { - Triggers = new[] { currencyRates.Base }, - Modifier = decimal.One, - UnitType = unitTypeString - }; - var toRemove = Units.Where(u => u.UnitType == unitTypeString); + var currencyRates = await GetCurrencyRates(); + var baseType = new ConvertUnit() + { + Triggers = new[] { currencyRates.Base }, + Modifier = decimal.One, + UnitType = unitTypeString + }; + var range = currencyRates.ConversionRates.Select(u => new ConvertUnit() + { + InternalTrigger = u.Key, + Modifier = u.Value, + UnitType = unitTypeString + }).ToArray(); + var toRemove = Units.Where(u => u.UnitType == unitTypeString); - using (var uow = _db.UnitOfWork) - { - uow.ConverterUnits.RemoveRange(toRemove.ToArray()); - uow.ConverterUnits.Add(baseType); - uow.ConverterUnits.AddRange(range); + using (var uow = _db.UnitOfWork) + { + uow.ConverterUnits.RemoveRange(toRemove.ToArray()); + uow.ConverterUnits.Add(baseType); + uow.ConverterUnits.AddRange(range); - await uow.CompleteAsync().ConfigureAwait(false); + await uow.CompleteAsync().ConfigureAwait(false); + } + Units.RemoveAll(u => u.UnitType == unitTypeString); + Units.Add(baseType); + Units.AddRange(range); + } + else + { + using (var uow = _db.UnitOfWork) + { + Units.RemoveAll(u => u.UnitType == unitTypeString); + Units.AddRange(uow.ConverterUnits.GetAll().ToArray()); + } } - Units.RemoveAll(u => u.UnitType == unitTypeString); - Units.Add(baseType); - Units.AddRange(range); - _log.Info("Updated Currency"); } catch { diff --git a/src/NadekoBot/Services/Utility/PatreonRewardsService.cs b/src/NadekoBot/Services/Utility/PatreonRewardsService.cs index 0f7105b7..f3811c6d 100644 --- a/src/NadekoBot/Services/Utility/PatreonRewardsService.cs +++ b/src/NadekoBot/Services/Utility/PatreonRewardsService.cs @@ -1,12 +1,15 @@ -using NadekoBot.Services.Database.Models; +using Discord.WebSocket; +using NadekoBot.Services.Database.Models; using NadekoBot.Services.Utility.Patreon; using Newtonsoft.Json; using NLog; using System; using System.Collections.Generic; using System.Collections.Immutable; +using System.IO; using System.Linq; using System.Net.Http; +using System.Text; using System.Threading; using System.Threading.Tasks; @@ -24,12 +27,13 @@ namespace NadekoBot.Services.Utility private readonly SemaphoreSlim claimLockJustInCase = new SemaphoreSlim(1, 1); private readonly Logger _log; - public readonly TimeSpan Interval = TimeSpan.FromMinutes(15); - private IBotCredentials _creds; + public readonly TimeSpan Interval = TimeSpan.FromMinutes(3); + private readonly IBotCredentials _creds; private readonly DbService _db; private readonly CurrencyService _currency; - public PatreonRewardsService(IBotCredentials creds, DbService db, CurrencyService currency) + public PatreonRewardsService(IBotCredentials creds, DbService db, CurrencyService currency, + DiscordSocketClient client) { _creds = creds; _db = db; @@ -37,58 +41,63 @@ namespace NadekoBot.Services.Utility if (string.IsNullOrWhiteSpace(creds.PatreonAccessToken)) return; _log = LogManager.GetCurrentClassLogger(); - Updater = new Timer(async (_) => await LoadPledges(), null, TimeSpan.Zero, Interval); + Updater = new Timer(async (load) => await RefreshPledges((bool)load), client.ShardId == 0, TimeSpan.Zero, Interval); } - public async Task LoadPledges() + public async Task RefreshPledges(bool shouldLoad) { - LastUpdate = DateTime.UtcNow; - await getPledgesLocker.WaitAsync(1000).ConfigureAwait(false); - try + if (shouldLoad) { - var rewards = new List(); - var users = new List(); - using (var http = new HttpClient()) + LastUpdate = DateTime.UtcNow; + await getPledgesLocker.WaitAsync().ConfigureAwait(false); + try { - http.DefaultRequestHeaders.Clear(); - http.DefaultRequestHeaders.Add("Authorization", "Bearer " + _creds.PatreonAccessToken); - var data = new PatreonData() + var rewards = new List(); + var users = new List(); + using (var http = new HttpClient()) { - Links = new PatreonDataLinks() + http.DefaultRequestHeaders.Clear(); + http.DefaultRequestHeaders.Add("Authorization", "Bearer " + _creds.PatreonAccessToken); + var data = new PatreonData() { - next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" - } - }; - do + Links = new PatreonDataLinks() + { + next = "https://api.patreon.com/oauth2/api/campaigns/334038/pledges" + } + }; + do + { + var res = await http.GetStringAsync(data.Links.next) + .ConfigureAwait(false); + data = JsonConvert.DeserializeObject(res); + var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); + rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject(x.ToString())) + .Where(x => x.attributes.declined_since == null)); + users.AddRange(data.Included + .Where(x => x["type"].ToString() == "user") + .Select(x => JsonConvert.DeserializeObject(x.ToString()))); + } while (!string.IsNullOrWhiteSpace(data.Links.next)); + } + Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() { - var res = await http.GetStringAsync(data.Links.next) - .ConfigureAwait(false); - data = JsonConvert.DeserializeObject(res); - var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge"); - rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject(x.ToString())) - .Where(x => x.attributes.declined_since == null)); - users.AddRange(data.Included - .Where(x => x["type"].ToString() == "user") - .Select(x => JsonConvert.DeserializeObject(x.ToString()))); - } while (!string.IsNullOrWhiteSpace(data.Links.next)); + User = y, + Reward = x, + }).ToImmutableArray(); + File.WriteAllText("./patreon_rewards.json", JsonConvert.SerializeObject(Pledges)); } - Pledges = rewards.Join(users, (r) => r.relationships?.patron?.data?.id, (u) => u.id, (x, y) => new PatreonUserAndReward() + catch (Exception ex) { - User = y, - Reward = x, - }).ToImmutableArray(); - } - catch (Exception ex) - { - _log.Warn(ex); - } - finally - { - var _ = Task.Run(async () => + _log.Warn(ex); + } + finally { - await Task.Delay(TimeSpan.FromMinutes(5)).ConfigureAwait(false); getPledgesLocker.Release(); - }); + } + } + else + { + Pledges = JsonConvert.DeserializeObject(File.ReadAllText("./patreon_rewards.json")) + .ToImmutableArray(); } } From 7ad5c5e02bf5cebf16141247f31e5eacdce0fd75 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 24 Jun 2017 05:24:43 +0200 Subject: [PATCH 18/26] Patreon rewards fix finished --- .../Modules/Utility/Commands/PatreonCommands.cs | 5 ++++- src/NadekoBot/NadekoBot.cs | 2 +- src/NadekoBot/Services/Utility/PatreonRewardsService.cs | 9 ++++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs index 509419fd..293e2c42 100644 --- a/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs +++ b/src/NadekoBot/Modules/Utility/Commands/PatreonCommands.cs @@ -34,7 +34,9 @@ namespace NadekoBot.Modules.Utility [OwnerOnly] public async Task PatreonRewardsReload() { - await _patreon.LoadPledges().ConfigureAwait(false); + if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken)) + return; + await _patreon.RefreshPledges(true).ConfigureAwait(false); await Context.Channel.SendConfirmAsync("👌").ConfigureAwait(false); } @@ -44,6 +46,7 @@ namespace NadekoBot.Modules.Utility { if (string.IsNullOrWhiteSpace(_creds.PatreonAccessToken)) return; + if (DateTime.UtcNow.Day < 5) { await ReplyErrorLocalized("clpa_too_early").ConfigureAwait(false); diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 2ee3d1b3..26cf6d91 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -163,7 +163,7 @@ namespace NadekoBot var repeaterService = new MessageRepeaterService(this, Client, AllGuildConfigs); //var converterService = new ConverterService(Db); var commandMapService = new CommandMapService(AllGuildConfigs); - var patreonRewardsService = new PatreonRewardsService(Credentials, Db, Currency); + var patreonRewardsService = new PatreonRewardsService(Credentials, Db, Currency, Client); var verboseErrorsService = new VerboseErrorsService(AllGuildConfigs, Db, CommandHandler, helpService); var pruneService = new PruneService(); #endregion diff --git a/src/NadekoBot/Services/Utility/PatreonRewardsService.cs b/src/NadekoBot/Services/Utility/PatreonRewardsService.cs index f3811c6d..8b463f7e 100644 --- a/src/NadekoBot/Services/Utility/PatreonRewardsService.cs +++ b/src/NadekoBot/Services/Utility/PatreonRewardsService.cs @@ -32,6 +32,8 @@ namespace NadekoBot.Services.Utility private readonly DbService _db; private readonly CurrencyService _currency; + private readonly string cacheFileName = "./patreon-rewards.json"; + public PatreonRewardsService(IBotCredentials creds, DbService db, CurrencyService currency, DiscordSocketClient client) { @@ -41,7 +43,8 @@ namespace NadekoBot.Services.Utility if (string.IsNullOrWhiteSpace(creds.PatreonAccessToken)) return; _log = LogManager.GetCurrentClassLogger(); - Updater = new Timer(async (load) => await RefreshPledges((bool)load), client.ShardId == 0, TimeSpan.Zero, Interval); + Updater = new Timer(async (load) => await RefreshPledges((bool)load), + client.ShardId == 0, client.ShardId == 0 ? TimeSpan.Zero : TimeSpan.FromMinutes(2), Interval); } public async Task RefreshPledges(bool shouldLoad) @@ -93,11 +96,15 @@ namespace NadekoBot.Services.Utility { getPledgesLocker.Release(); } + Console.WriteLine("Pledges loaded from the website"); } else { + if(File.Exists(cacheFileName)) Pledges = JsonConvert.DeserializeObject(File.ReadAllText("./patreon_rewards.json")) .ToImmutableArray(); + + Console.WriteLine("Pledges loaded from the file"); } } From e27e1005eb3443549663cfaed89b69ef2ed35ac1 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sat, 24 Jun 2017 07:23:59 +0200 Subject: [PATCH 19/26] poll is now public poll, private poll removed --- .../Modules/Games/Commands/PollCommands.cs | 19 ++---- src/NadekoBot/NadekoBot.cs | 20 +++++- .../Services/Administration/SelfService.cs | 64 +++++++++---------- src/NadekoBot/Services/Games/Poll.cs | 46 +++---------- src/NadekoBot/Services/Games/PollService.cs | 14 +--- .../Services/Utility/ConverterService.cs | 1 - .../Services/Utility/PatreonRewardsService.cs | 4 -- src/NadekoBot/ShardsCoordinator.cs | 2 +- 8 files changed, 64 insertions(+), 106 deletions(-) diff --git a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs index 27dbb03c..0d6b6cb2 100644 --- a/src/NadekoBot/Modules/Games/Commands/PollCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PollCommands.cs @@ -26,13 +26,7 @@ namespace NadekoBot.Modules.Games [RequireUserPermission(GuildPermission.ManageMessages)] [RequireContext(ContextType.Guild)] public Task Poll([Remainder] string arg = null) - => InternalStartPoll(arg, false); - - [NadekoCommand, Usage, Description, Aliases] - [RequireUserPermission(GuildPermission.ManageMessages)] - [RequireContext(ContextType.Guild)] - public Task PublicPoll([Remainder] string arg = null) - => InternalStartPoll(arg, true); + => InternalStartPoll(arg); [NadekoCommand, Usage, Description, Aliases] [RequireUserPermission(GuildPermission.ManageMessages)] @@ -44,15 +38,10 @@ namespace NadekoBot.Modules.Games await Context.Channel.EmbedAsync(poll.GetStats(GetText("current_poll_results"))); } - //todo enable private polls, or completely remove them - private async Task InternalStartPoll(string arg, bool isPublic = false) + + private async Task InternalStartPoll(string arg) { - if (isPublic == false) - { - await ReplyErrorLocalized($"Temporarily disabled. Use `{Prefix}ppoll`"); - return; - } - if(await _polls.StartPoll((ITextChannel)Context.Channel, Context.Message, arg, isPublic) == false) + if(await _polls.StartPoll((ITextChannel)Context.Channel, Context.Message, arg) == false) await ReplyErrorLocalized("poll_already_running").ConfigureAwait(false); } diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 26cf6d91..24033c1f 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -290,9 +290,23 @@ namespace NadekoBot Task SetClientReady() { - var _ = Task.Run(() => + var _ = Task.Run(async () => { clientReady.TrySetResult(true); + try + { + await Task.WhenAll((await Client.GetDMChannelsAsync()) + .Select(x => x.CloseAsync())) + .ConfigureAwait(false); + } + catch + { + // ignored + } + finally + { + + } }); return Task.CompletedTask; } @@ -304,8 +318,8 @@ namespace NadekoBot try { - Client.LoginAsync(TokenType.Bot, token).GetAwaiter().GetResult(); - Client.StartAsync().GetAwaiter().GetResult(); + await Client.LoginAsync(TokenType.Bot, token).ConfigureAwait(false); + await Client.StartAsync().ConfigureAwait(false); Client.Ready += SetClientReady; await clientReady.Task.ConfigureAwait(false); Client.Ready -= SetClientReady; diff --git a/src/NadekoBot/Services/Administration/SelfService.cs b/src/NadekoBot/Services/Administration/SelfService.cs index 336f9970..2a12ffca 100644 --- a/src/NadekoBot/Services/Administration/SelfService.cs +++ b/src/NadekoBot/Services/Administration/SelfService.cs @@ -63,44 +63,44 @@ namespace NadekoBot.Services.Administration _client.Guilds.SelectMany(g => g.Users); - //todo load owner channels - //LoadOwnerChannels(); + if(client.ShardId == 0) + LoadOwnerChannels(); }); } - //private void LoadOwnerChannels() - //{ - // var hs = new HashSet(_creds.OwnerIds); - // var channels = new Dictionary>(); + private void LoadOwnerChannels() + { + var hs = new HashSet(_creds.OwnerIds); + var channels = new Dictionary>(); - // if (hs.Count > 0) - // { - // foreach (var g in _client.Guilds) - // { - // if (hs.Count == 0) - // break; + if (hs.Count > 0) + { + foreach (var g in _client.Guilds) + { + if (hs.Count == 0) + break; - // foreach (var u in g.Users) - // { - // if (hs.Remove(u.Id)) - // { - // channels.Add(u.Id, new AsyncLazy(async () => await u.CreateDMChannelAsync())); - // if (hs.Count == 0) - // break; - // } - // } - // } - // } - - // ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key)) - // .Select(x => x.Value) - // .ToImmutableArray(); + foreach (var u in g.Users) + { + if (hs.Remove(u.Id)) + { + channels.Add(u.Id, new AsyncLazy(async () => await u.CreateDMChannelAsync())); + if (hs.Count == 0) + break; + } + } + } + } - // if (!ownerChannels.Any()) - // _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); - // else - // _log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels."); - //} + ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key)) + .Select(x => x.Value) + .ToImmutableArray(); + + if (!ownerChannels.Any()) + _log.Warn("No owner channels created! Make sure you've specified correct OwnerId in the credentials.json file."); + else + _log.Info($"Created {ownerChannels.Length} out of {_creds.OwnerIds.Length} owner message channels."); + } // forwards dms public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg) diff --git a/src/NadekoBot/Services/Games/Poll.cs b/src/NadekoBot/Services/Games/Poll.cs index 1a6bbf20..5358e139 100644 --- a/src/NadekoBot/Services/Games/Poll.cs +++ b/src/NadekoBot/Services/Games/Poll.cs @@ -21,13 +21,10 @@ namespace NadekoBot.Services.Games private readonly DiscordSocketClient _client; private readonly NadekoStrings _strings; private bool running = false; - private HashSet _guildUsers; public event Action OnEnded = delegate { }; - public bool IsPublic { get; } - - public Poll(DiscordSocketClient client, NadekoStrings strings, IUserMessage umsg, string question, IEnumerable enumerable, bool isPublic = false) + public Poll(DiscordSocketClient client, NadekoStrings strings, IUserMessage umsg, string question, IEnumerable enumerable) { _client = client; _strings = strings; @@ -36,7 +33,6 @@ namespace NadekoBot.Services.Games _guild = ((ITextChannel)umsg.Channel).Guild; _question = question; answers = enumerable as string[] ?? enumerable.ToArray(); - IsPublic = isPublic; } public EmbedBuilder GetStats(string title) @@ -82,13 +78,7 @@ namespace NadekoBot.Services.Games var msgToSend = GetText("poll_created", Format.Bold(_originalMessage.Author.Username)) + "\n\n" + Format.Bold(_question) + "\n"; var num = 1; msgToSend = answers.Aggregate(msgToSend, (current, answ) => current + $"`{num++}.` **{answ}**\n"); - if (!IsPublic) - msgToSend += "\n" + Format.Bold(GetText("poll_vote_private")); - else - msgToSend += "\n" + Format.Bold(GetText("poll_vote_public")); - - if (!IsPublic) - _guildUsers = new HashSet((await _guild.GetUsersAsync().ConfigureAwait(false)).Select(x => x.Id)); + msgToSend += "\n" + Format.Bold(GetText("poll_vote_public")); await _originalMessage.Channel.SendConfirmAsync(msgToSend).ConfigureAwait(false); running = true; @@ -114,36 +104,16 @@ namespace NadekoBot.Services.Games return false; IMessageChannel ch; - if (IsPublic) - { - //if public, channel must be the same the poll started in - if (_originalMessage.Channel.Id != msg.Channel.Id) - return false; - ch = msg.Channel; - } - else - { - //if private, channel must be dm channel - if ((ch = msg.Channel as IDMChannel) == null) - return false; - - // user must be a member of the guild this poll is in - if (!_guildUsers.Contains(msg.Author.Id)) - return false; - } + //if public, channel must be the same the poll started in + if (_originalMessage.Channel.Id != msg.Channel.Id) + return false; + ch = msg.Channel; //user can vote only once if (_participants.TryAdd(msg.Author.Id, vote)) { - if (!IsPublic) - { - await ch.SendConfirmAsync(GetText("thanks_for_voting", Format.Bold(msg.Author.Username))).ConfigureAwait(false); - } - else - { - var toDelete = await ch.SendConfirmAsync(GetText("poll_voted", Format.Bold(msg.Author.ToString()))).ConfigureAwait(false); - toDelete.DeleteAfter(5); - } + var toDelete = await ch.SendConfirmAsync(GetText("poll_voted", Format.Bold(msg.Author.ToString()))).ConfigureAwait(false); + toDelete.DeleteAfter(5); return true; } return false; diff --git a/src/NadekoBot/Services/Games/PollService.cs b/src/NadekoBot/Services/Games/PollService.cs index ce8852a7..ba6fee19 100644 --- a/src/NadekoBot/Services/Games/PollService.cs +++ b/src/NadekoBot/Services/Games/PollService.cs @@ -23,7 +23,7 @@ namespace NadekoBot.Services.Games _strings = strings; } - public async Task StartPoll(ITextChannel channel, IUserMessage msg, string arg, bool isPublic = false) + public async Task StartPoll(ITextChannel channel, IUserMessage msg, string arg) { if (string.IsNullOrWhiteSpace(arg) || !arg.Contains(";")) return null; @@ -31,7 +31,7 @@ namespace NadekoBot.Services.Games if (data.Length < 3) return null; - var poll = new Poll(_client, _strings, msg, data[0], data.Skip(1), isPublic: isPublic); + var poll = new Poll(_client, _strings, msg, data[0], data.Skip(1)); if (ActivePolls.TryAdd(channel.Guild.Id, poll)) { poll.OnEnded += (gid) => @@ -48,17 +48,7 @@ namespace NadekoBot.Services.Games public async Task TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg) { if (guild == null) - { - foreach (var kvp in ActivePolls) - { - if (!kvp.Value.IsPublic) - { - if (await kvp.Value.TryVote(msg).ConfigureAwait(false)) - return true; - } - } return false; - } if (!ActivePolls.TryGetValue(guild.Id, out var poll)) return false; diff --git a/src/NadekoBot/Services/Utility/ConverterService.cs b/src/NadekoBot/Services/Utility/ConverterService.cs index 1edb470a..40f7fafa 100644 --- a/src/NadekoBot/Services/Utility/ConverterService.cs +++ b/src/NadekoBot/Services/Utility/ConverterService.cs @@ -18,7 +18,6 @@ namespace NadekoBot.Services.Utility public List Units { get; } = new List(); private readonly Logger _log; private readonly Timer _currencyUpdater; - private readonly Timer _currencyLoader; private readonly TimeSpan _updateInterval = new TimeSpan(12, 0, 0); private readonly DbService _db; diff --git a/src/NadekoBot/Services/Utility/PatreonRewardsService.cs b/src/NadekoBot/Services/Utility/PatreonRewardsService.cs index 8b463f7e..3eef3d72 100644 --- a/src/NadekoBot/Services/Utility/PatreonRewardsService.cs +++ b/src/NadekoBot/Services/Utility/PatreonRewardsService.cs @@ -15,7 +15,6 @@ using System.Threading.Tasks; namespace NadekoBot.Services.Utility { - //todo periodically load from the database, update only on shard 0 public class PatreonRewardsService { private readonly SemaphoreSlim getPledgesLocker = new SemaphoreSlim(1, 1); @@ -96,15 +95,12 @@ namespace NadekoBot.Services.Utility { getPledgesLocker.Release(); } - Console.WriteLine("Pledges loaded from the website"); } else { if(File.Exists(cacheFileName)) Pledges = JsonConvert.DeserializeObject(File.ReadAllText("./patreon_rewards.json")) .ToImmutableArray(); - - Console.WriteLine("Pledges loaded from the file"); } } diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs index 3fe6da58..fcf80ebe 100644 --- a/src/NadekoBot/ShardsCoordinator.cs +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -53,7 +53,7 @@ namespace NadekoBot FileName = Credentials.ShardRunCommand, Arguments = string.Format(Credentials.ShardRunArguments, i, curProcessId) }); - await Task.Delay(6500); + await Task.Delay(5000); } } From f11429b7146212ac4030b02a8734951e7ea13ba4 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 25 Jun 2017 01:45:11 +0200 Subject: [PATCH 20/26] anilist api should work a bit better and is cleaner --- .../Services/Searches/AnimeSearchService.cs | 59 +++---------------- 1 file changed, 9 insertions(+), 50 deletions(-) diff --git a/src/NadekoBot/Services/Searches/AnimeSearchService.cs b/src/NadekoBot/Services/Searches/AnimeSearchService.cs index 2e4ef756..a4187da3 100644 --- a/src/NadekoBot/Services/Searches/AnimeSearchService.cs +++ b/src/NadekoBot/Services/Searches/AnimeSearchService.cs @@ -1,53 +1,18 @@ using Newtonsoft.Json; -using Newtonsoft.Json.Linq; using NLog; using System; -using System.Collections.Generic; -using System.Linq; using System.Net.Http; -using System.Text; -using System.Threading; using System.Threading.Tasks; namespace NadekoBot.Services.Searches { - //todo move to the website public class AnimeSearchService { - private readonly Timer _anilistTokenRefresher; private readonly Logger _log; - private static string anilistToken { get; set; } - public AnimeSearchService() { _log = LogManager.GetCurrentClassLogger(); - _anilistTokenRefresher = new Timer(async (state) => - { - try - { - var headers = new Dictionary - { - {"grant_type", "client_credentials"}, - {"client_id", "kwoth-w0ki9"}, - {"client_secret", "Qd6j4FIAi1ZK6Pc7N7V4Z"}, - }; - - using (var http = new HttpClient()) - { - //http.AddFakeHeaders(); - http.DefaultRequestHeaders.Clear(); - var formContent = new FormUrlEncodedContent(headers); - var response = await http.PostAsync("https://anilist.co/api/auth/access_token", formContent).ConfigureAwait(false); - var stringContent = await response.Content.ReadAsStringAsync().ConfigureAwait(false); - anilistToken = JObject.Parse(stringContent)["access_token"].ToString(); - } - } - catch - { - // ignored - } - }, null, TimeSpan.FromSeconds(0), TimeSpan.FromMinutes(29)); } public async Task GetAnimeData(string query) @@ -57,19 +22,15 @@ namespace NadekoBot.Services.Searches try { - var link = "http://anilist.co/api/anime/search/" + Uri.EscapeUriString(query); + var link = "https://aniapi.nadekobot.me/anime/" + Uri.EscapeDataString(query.Replace("/", " ")); using (var http = new HttpClient()) { - var res = await http.GetStringAsync(link + $"?access_token={anilistToken}").ConfigureAwait(false); - var smallObj = JArray.Parse(res)[0]; - var aniData = await http.GetStringAsync("http://anilist.co/api/anime/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false); - - return await Task.Run(() => { try { return JsonConvert.DeserializeObject(aniData); } catch { return null; } }).ConfigureAwait(false); + var res = await http.GetStringAsync(link).ConfigureAwait(false); + return JsonConvert.DeserializeObject(res); } } - catch (Exception ex) + catch { - _log.Warn(ex, "Failed anime search for {0}", query); return null; } } @@ -80,18 +41,16 @@ namespace NadekoBot.Services.Searches throw new ArgumentNullException(nameof(query)); try { + + var link = "https://aniapi.nadekobot.me/manga/" + Uri.EscapeDataString(query.Replace("/", " ")); using (var http = new HttpClient()) { - var res = await http.GetStringAsync("http://anilist.co/api/manga/search/" + Uri.EscapeUriString(query) + $"?access_token={anilistToken}").ConfigureAwait(false); - var smallObj = JArray.Parse(res)[0]; - var aniData = await http.GetStringAsync("http://anilist.co/api/manga/" + smallObj["id"] + $"?access_token={anilistToken}").ConfigureAwait(false); - - return await Task.Run(() => { try { return JsonConvert.DeserializeObject(aniData); } catch { return null; } }).ConfigureAwait(false); + var res = await http.GetStringAsync(link).ConfigureAwait(false); + return JsonConvert.DeserializeObject(res); } } - catch (Exception ex) + catch { - _log.Warn(ex, "Failed anime search for {0}", query); return null; } } From e1baa3942a2161f77dbc9878c2eb7176b23d3ed9 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 25 Jun 2017 02:35:37 +0200 Subject: [PATCH 21/26] .gc and stream follows should properly persist restarts --- .../Modules/Administration/Commands/SelfCommands.cs | 8 ++++---- .../Modules/Games/Commands/PlantAndPickCommands.cs | 2 +- src/NadekoBot/Modules/Utility/Utility.cs | 2 -- src/NadekoBot/NadekoBot.cs | 11 ++++------- src/NadekoBot/Resources/CommandStrings.resx | 10 +++++----- .../Repositories/Impl/GuildConfigRepository.cs | 1 + 6 files changed, 15 insertions(+), 19 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs index 5e5ecb33..449398b4 100644 --- a/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs +++ b/src/NadekoBot/Modules/Administration/Commands/SelfCommands.cs @@ -14,6 +14,7 @@ using NadekoBot.Services.Database.Models; using Microsoft.EntityFrameworkCore; using NadekoBot.Services.Administration; using System.Diagnostics; +using NadekoBot.DataStructures; namespace NadekoBot.Modules.Administration { @@ -207,12 +208,11 @@ namespace NadekoBot.Modules.Administration //todo 2 shard commands //[NadekoCommand, Usage, Description, Aliases] + //[Shard0Precondition] //[OwnerOnly] - //public async Task ConnectShard(int shardid) + //public async Task RestartShard(int shardid) //{ - // var shard = _client.GetShard(shardid); - - // if (shard == null) + // if (shardid == 0 || shardid > b) // { // await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false); // return; diff --git a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs index 191fd30d..f055e0bb 100644 --- a/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs +++ b/src/NadekoBot/Modules/Games/Commands/PlantAndPickCommands.cs @@ -116,7 +116,7 @@ namespace NadekoBot.Modules.Games bool enabled; using (var uow = _db.UnitOfWork) { - var guildConfig = uow.GuildConfigs.For(channel.Id, set => set.Include(gc => gc.GenerateCurrencyChannelIds)); + var guildConfig = uow.GuildConfigs.For(channel.Guild.Id, set => set.Include(gc => gc.GenerateCurrencyChannelIds)); var toAdd = new GCChannelId() { ChannelId = channel.Id }; if (!guildConfig.GenerateCurrencyChannelIds.Contains(toAdd)) diff --git a/src/NadekoBot/Modules/Utility/Utility.cs b/src/NadekoBot/Modules/Utility/Utility.cs index 3ae25163..7a6f9ae1 100644 --- a/src/NadekoBot/Modules/Utility/Utility.cs +++ b/src/NadekoBot/Modules/Utility/Utility.cs @@ -299,8 +299,6 @@ namespace NadekoBot.Modules.Utility Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.ToString()))) .ToArray(); - - await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) => { diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 24033c1f..a180f3b5 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -4,8 +4,6 @@ using Discord.WebSocket; using NadekoBot.Services; using NadekoBot.Services.Impl; using NLog; -using NLog.Config; -using NLog.Targets; using System; using System.Linq; using System.Reflection; @@ -28,8 +26,6 @@ using NadekoBot.Services.Help; using System.IO; using NadekoBot.Services.Pokemon; using NadekoBot.DataStructures.ShardCom; -using NadekoBot.DataStructures; -using NadekoBot.Extensions; namespace NadekoBot { @@ -295,9 +291,10 @@ namespace NadekoBot clientReady.TrySetResult(true); try { - await Task.WhenAll((await Client.GetDMChannelsAsync()) - .Select(x => x.CloseAsync())) - .ConfigureAwait(false); + foreach (var chan in (await Client.GetDMChannelsAsync())) + { + await chan.CloseAsync().ConfigureAwait(false); + } } catch { diff --git a/src/NadekoBot/Resources/CommandStrings.resx b/src/NadekoBot/Resources/CommandStrings.resx index 708abfe8..e896535d 100644 --- a/src/NadekoBot/Resources/CommandStrings.resx +++ b/src/NadekoBot/Resources/CommandStrings.resx @@ -3096,14 +3096,14 @@ `{0}shardstats` or `{0}shardstats 2` - - connectshard + + restartshard - + Try (re)connecting a shard with a certain shardid when it dies. No one knows will it work. Keep an eye on the console for errors. - - `{0}connectshard 2` + + `{0}restartshard 2` shardid diff --git a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs index 37d2af60..3628a4e9 100644 --- a/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs +++ b/src/NadekoBot/Services/Database/Repositories/Impl/GuildConfigRepository.cs @@ -44,6 +44,7 @@ namespace NadekoBot.Services.Database.Repositories.Impl .Include(gc => gc.SlowmodeIgnoredUsers) .Include(gc => gc.AntiSpamSetting) .ThenInclude(x => x.IgnoredChannels) + .Include(gc => gc.FollowedStreams) .ToList(); /// From 3f2eef5647fabdd05949e5324cd10f5bf6cd09cf Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 25 Jun 2017 02:39:31 +0200 Subject: [PATCH 22/26] .ve now properly persists restarts --- .../Services/Utility/VerboseErrorsService.cs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/NadekoBot/Services/Utility/VerboseErrorsService.cs b/src/NadekoBot/Services/Utility/VerboseErrorsService.cs index 009de8ee..7658ea1c 100644 --- a/src/NadekoBot/Services/Utility/VerboseErrorsService.cs +++ b/src/NadekoBot/Services/Utility/VerboseErrorsService.cs @@ -50,12 +50,12 @@ namespace NadekoBot.Services.Utility public bool ToggleVerboseErrors(ulong guildId) { - + bool enabled; using (var uow = _db.UnitOfWork) { var gc = uow.GuildConfigs.For(guildId, set => set); - gc.VerboseErrors = !gc.VerboseErrors; + enabled = gc.VerboseErrors = !gc.VerboseErrors; uow.Complete(); @@ -65,15 +65,12 @@ namespace NadekoBot.Services.Utility guildsEnabled.TryRemove(guildId); } - if (guildsEnabled.Add(guildId)) - { - return true; - } + if (enabled) + guildsEnabled.Add(guildId); else - { guildsEnabled.TryRemove(guildId); - return false; - } + + return enabled; } } From ff56af3e736421f2ad018bd1ab454595c4e2af2d Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 25 Jun 2017 03:56:23 +0200 Subject: [PATCH 23/26] .rar fixed, closes #1306 --- src/NadekoBot/Modules/Administration/Administration.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NadekoBot/Modules/Administration/Administration.cs b/src/NadekoBot/Modules/Administration/Administration.cs index 15185ca3..56a0affc 100644 --- a/src/NadekoBot/Modules/Administration/Administration.cs +++ b/src/NadekoBot/Modules/Administration/Administration.cs @@ -126,17 +126,17 @@ namespace NadekoBot.Modules.Administration { var guser = (IGuildUser)Context.User; - var userRoles = user.GetRoles(); - if (guser.Id != Context.Guild.OwnerId && - (user.Id == Context.Guild.OwnerId || guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position))) + var userRoles = user.GetRoles().Except(new[] { guser.Guild.EveryoneRole }); + if (user.Id == Context.Guild.OwnerId || (Context.User.Id != Context.Guild.OwnerId && guser.GetRoles().Max(x => x.Position) <= userRoles.Max(x => x.Position))) return; try { await user.RemoveRolesAsync(userRoles).ConfigureAwait(false); await ReplyConfirmLocalized("rar", Format.Bold(user.ToString())).ConfigureAwait(false); } - catch + catch (Exception ex) { + Console.WriteLine(ex); await ReplyErrorLocalized("rar_err").ConfigureAwait(false); } } From 902ddc70f609c17349276ccbd10deb2df46ab7d7 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 25 Jun 2017 04:58:48 +0200 Subject: [PATCH 24/26] triggered permissions are now translatable --- src/NadekoBot/NadekoBot.cs | 6 +++--- .../Services/CustomReactions/CustomReactionsService.cs | 6 ++++-- src/NadekoBot/Services/Games/ChatterbotService.cs | 7 +++++-- src/NadekoBot/Services/Permissions/PermissionsService.cs | 9 ++++----- src/NadekoBot/_strings/ResponseStrings.en-US.json | 7 ++++--- 5 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index a180f3b5..4142aa2f 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -165,7 +165,7 @@ namespace NadekoBot #endregion #region permissions - var permissionsService = new PermissionService(Client, Db, BotConfig, CommandHandler); + var permissionsService = new PermissionService(Client, Db, BotConfig, CommandHandler, Strings); var blacklistService = new BlacklistService(BotConfig); var cmdcdsService = new CmdCdService(AllGuildConfigs); var filterService = new FilterService(Client, AllGuildConfigs); @@ -180,11 +180,11 @@ namespace NadekoBot var clashService = new ClashOfClansService(Client, Db, Localization, Strings, uow, startingGuildIdList); var musicService = new MusicService(GoogleApi, Strings, Localization, Db, soundcloudApiService, Credentials, AllGuildConfigs); - var crService = new CustomReactionsService(permissionsService, Db, Client, CommandHandler, BotConfig, uow); + var crService = new CustomReactionsService(permissionsService, Db, Strings, Client, CommandHandler, BotConfig, uow); #region Games var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, Strings, Images, CommandHandler); - var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs, CommandHandler); + var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs, CommandHandler, Strings); var pollService = new PollService(Client, Strings); #endregion diff --git a/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs b/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs index ecf0dede..c64f5c81 100644 --- a/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs +++ b/src/NadekoBot/Services/CustomReactions/CustomReactionsService.cs @@ -27,8 +27,9 @@ namespace NadekoBot.Services.CustomReactions private readonly PermissionService _perms; private readonly CommandHandler _cmd; private readonly BotConfig _bc; + private readonly NadekoStrings _strings; - public CustomReactionsService(PermissionService perms, DbService db, + public CustomReactionsService(PermissionService perms, DbService db, NadekoStrings strings, DiscordSocketClient client, CommandHandler cmd, BotConfig bc, IUnitOfWork uow) { _log = LogManager.GetCurrentClassLogger(); @@ -37,6 +38,7 @@ namespace NadekoBot.Services.CustomReactions _perms = perms; _cmd = cmd; _bc = bc; + _strings = strings; var items = uow.CustomReactions.GetAll(); GuildReactions = new ConcurrentDictionary(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray())); @@ -109,7 +111,7 @@ namespace NadekoBot.Services.CustomReactions { if (pc.Verbose) { - var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), sg)}** is preventing this action."; + var returnMsg = _strings.GetText("trigger", guild.Id, "Permissions".ToLowerInvariant(), index + 1, Format.Bold(pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild))); try { await msg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { } _log.Info(returnMsg); } diff --git a/src/NadekoBot/Services/Games/ChatterbotService.cs b/src/NadekoBot/Services/Games/ChatterbotService.cs index ad295dec..833eef0b 100644 --- a/src/NadekoBot/Services/Games/ChatterbotService.cs +++ b/src/NadekoBot/Services/Games/ChatterbotService.cs @@ -19,15 +19,18 @@ namespace NadekoBot.Services.Games private readonly Logger _log; private readonly PermissionService _perms; private readonly CommandHandler _cmd; + private readonly NadekoStrings _strings; public ConcurrentDictionary> ChatterBotGuilds { get; } - public ChatterBotService(DiscordSocketClient client, PermissionService perms, IEnumerable gcs, CommandHandler cmd) + public ChatterBotService(DiscordSocketClient client, PermissionService perms, IEnumerable gcs, + CommandHandler cmd, NadekoStrings strings) { _client = client; _log = LogManager.GetCurrentClassLogger(); _perms = perms; _cmd = cmd; + _strings = strings; ChatterBotGuilds = new ConcurrentDictionary>( gcs.Where(gc => gc.CleverbotEnabled) @@ -102,7 +105,7 @@ namespace NadekoBot.Services.Games if (pc.Verbose) { //todo move this to permissions - var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), sg)}** is preventing this action."; + var returnMsg = _strings.GetText("trigger", guild.Id, "Permissions".ToLowerInvariant(), index + 1, Format.Bold(pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild))); try { await usrMsg.Channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { } _log.Info(returnMsg); } diff --git a/src/NadekoBot/Services/Permissions/PermissionsService.cs b/src/NadekoBot/Services/Permissions/PermissionsService.cs index 00794d2d..c4c586a9 100644 --- a/src/NadekoBot/Services/Permissions/PermissionsService.cs +++ b/src/NadekoBot/Services/Permissions/PermissionsService.cs @@ -20,16 +20,18 @@ namespace NadekoBot.Services.Permissions private readonly DbService _db; private readonly Logger _log; private readonly CommandHandler _cmd; + private readonly NadekoStrings _strings; //guildid, root permission public ConcurrentDictionary Cache { get; } = new ConcurrentDictionary(); - public PermissionService(DiscordSocketClient client, DbService db, BotConfig bc, CommandHandler cmd) + public PermissionService(DiscordSocketClient client, DbService db, BotConfig bc, CommandHandler cmd, NadekoStrings strings) { _log = LogManager.GetCurrentClassLogger(); _db = db; _cmd = cmd; + _strings = strings; var sw = Stopwatch.StartNew(); if (client.ShardId == 0) @@ -205,11 +207,9 @@ WHERE secondaryTargetName LIKE '.%' OR PermissionCache pc = GetCache(guild.Id); if (!resetCommand && !pc.Permissions.CheckPermissions(msg, commandName, moduleName, out int index)) { - var returnMsg = $"Permission number #{index + 1} **{pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild)}** is preventing this action."; if (pc.Verbose) - try { await channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { } + try { await channel.SendErrorAsync(_strings.GetText("trigger", guild.Id, "Permissions".ToLowerInvariant(), index + 1, Format.Bold(pc.Permissions[index].GetCommand(_cmd.GetPrefix(guild), (SocketGuild)guild)))).ConfigureAwait(false); } catch { } return true; - //return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, returnMsg)); } @@ -222,7 +222,6 @@ WHERE secondaryTargetName LIKE '.%' OR if (pc.Verbose) try { await channel.SendErrorAsync(returnMsg).ConfigureAwait(false); } catch { } return true; - //return new ExecuteCommandResult(cmd, pc, SearchResult.FromError(CommandError.Exception, $"You need the **{pc.PermRole}** role in order to use permission commands.")); } } } diff --git a/src/NadekoBot/_strings/ResponseStrings.en-US.json b/src/NadekoBot/_strings/ResponseStrings.en-US.json index d1863403..f405c63e 100644 --- a/src/NadekoBot/_strings/ResponseStrings.en-US.json +++ b/src/NadekoBot/_strings/ResponseStrings.en-US.json @@ -154,6 +154,7 @@ "administration_old_topic": "Old topic", "administration_perms": "Error. Most likely I don't have sufficient permissions.", "permissions_perms_reset": "Permissions for this server are reset.", + "permissions_trigger": "Permission number #{0} {1} is preventing this action.", "administration_prot_active": "Active protections", "administration_prot_disable": "{0} has been **disabled** on this server.", "administration_prot_enable": "{0} Enabled", @@ -446,7 +447,7 @@ "music_skipped_to": "Skipped to `{0}:{1}`", "music_songs_shuffled": "Songs shuffled", "music_song_moved": "Song moved", - "music_song_not_found": "No song found.", + "music_song_not_found": "No song found.", "music_time_format": "{0}h {1}m {2}s", "music_to_position": "To position", "music_unlimited": "unlimited", @@ -523,7 +524,7 @@ "searches_cost": "Cost", "searches_date": "Date", "searches_define": "Define:", - "searches_define_unknown": "Can't find the definition for that term.", + "searches_define_unknown": "Can't find the definition for that term.", "searches_dropped": "Dropped", "searches_episodes": "Episodes", "searches_error_occured": "Error occurred.", @@ -534,7 +535,7 @@ "searches_hashtag_error": "Failed finding a definition for that tag.", "searches_height_weight": "Height/Weight", "searches_height_weight_val": "{0}m/{1}kg", - "searches_hex_invalid": "Invalid color specified.", + "searches_hex_invalid": "Invalid color specified.", "searches_humidity": "Humidity", "searches_image_search_for": "Image search for:", "searches_imdb_fail": "Failed to find that movie.", From ee8643bf29aae08840020651ec4a0812734bffdf Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 25 Jun 2017 06:09:23 +0200 Subject: [PATCH 25/26] You can now choose port where shard communication is happening. JSON explanations with instructions on how to ed it optional shard settings --- NadekoBot.sln | 2 +- docs/JSON Explanations.md | 24 +++++++++++++++---- .../DataStructures/ShardCom/ShardComClient.cs | 9 ++++++- .../DataStructures/ShardCom/ShardComServer.cs | 8 +++++-- src/NadekoBot/NadekoBot.cs | 14 +++++++---- src/NadekoBot/Program.cs | 9 +++++-- src/NadekoBot/Services/Impl/BotCredentials.cs | 13 ++++++++-- src/NadekoBot/Services/Impl/StatsService.cs | 2 +- src/NadekoBot/ShardsCoordinator.cs | 8 ++++--- src/NadekoBot/credentials_example.json | 4 +++- 10 files changed, 71 insertions(+), 22 deletions(-) diff --git a/NadekoBot.sln b/NadekoBot.sln index a80335e2..8c235940 100644 --- a/NadekoBot.sln +++ b/NadekoBot.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 -VisualStudioVersion = 15.0.26430.6 +VisualStudioVersion = 15.0.26430.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{04929013-5BAB-42B0-B9B2-8F2BB8F16AF2}" EndProject diff --git a/docs/JSON Explanations.md b/docs/JSON Explanations.md index 363c5e8d..bf84432d 100644 --- a/docs/JSON Explanations.md +++ b/docs/JSON Explanations.md @@ -17,7 +17,8 @@ If you do not see `credentials.json` you will need to rename `credentials_exampl "MashapeKey": "4UrKpcWXc2mshS8RKi00000y8Kf5p1Q8kI6jsn32bmd8oVWiY7", "OsuApiKey": "4c8c8fdff8e1234581725db27fd140a7d93320d6", "Db": null, - "TotalShards": 1 + "TotalShards": 1, + "ShardRunCommand": "" } ``` ----- @@ -143,14 +144,29 @@ It should look like: - **TotalShards** - Required if the bot will be connected to more than 1500 servers. - Most likely unnecessary to change until your bot is added to more than 1500 servers. - +- **ShardRunCommand** + - Required if you're sharding your bot on windows using .exe, or in a custom way. + - This internally defaults to `dotnet` + - For example, if you want to shard your NadekoBot which you installed using windows installer, you would want to set it to something like this: `C:\Program Files\NadekoBot\system\NadekoBot.exe` +- **ShardRunArguments** + - Required if you're sharding your bot on windows using .exe, or in a custom way. + - This internally defaults to `run -c Release -- {0} {1} {2}` which will be enough to run linux and other 'from source' setups + - {0} will be replaced by the `shard ID` of the shard being ran, {1} by the shard 0's process id, and {2} by the port shard communication is happening on + - If shard0 (main window) is closed, all other shards will close too + - For example, if you want to shard your NadekoBot which you installed using windows installer, you would want to set it to `{0} {1} {2}` +- **ShardRunPort** + - Bot uses a random UDP port in [5000, 6000) range for communication between shards ----- ## DB files -Nadeko saves all the settings and infomations in `NadekoBot.db` file here: +Nadeko saves all the settings and infomations in `NadekoBot.db` file here: +**On linux** `NadekoBot\src\NadekoBot\bin\Release\netcoreapp1.1\data\NadekoBot.db` (NadekoBot v1.4x) -in order to open the database file you will need [DB Browser for SQLite](http://sqlitebrowser.org/). +**On windows** +`[INSTALL_PATH]\NadekoBot\system\data\NadekoBot.db` + +In order to open the database file you will need [DB Browser for SQLite](http://sqlitebrowser.org/). To make changes diff --git a/src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs b/src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs index a8857f3e..67e1c9f6 100644 --- a/src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs +++ b/src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs @@ -9,13 +9,20 @@ namespace NadekoBot.DataStructures.ShardCom { public class ShardComClient { + private int port; + + public ShardComClient(int port) + { + this.port = port; + } + public async Task Send(ShardComMessage data) { var msg = JsonConvert.SerializeObject(data); using (var client = new UdpClient()) { var bytes = Encoding.UTF8.GetBytes(msg); - await client.SendAsync(bytes, bytes.Length, IPAddress.Loopback.ToString(), ShardComServer.Port).ConfigureAwait(false); + await client.SendAsync(bytes, bytes.Length, IPAddress.Loopback.ToString(), port).ConfigureAwait(false); } } } diff --git a/src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs b/src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs index 61c35a85..d0e1cbf6 100644 --- a/src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs +++ b/src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs @@ -9,8 +9,12 @@ namespace NadekoBot.DataStructures.ShardCom { public class ShardComServer : IDisposable { - public const int Port = 5664; - private readonly UdpClient _client = new UdpClient(Port); + private readonly UdpClient _client; + + public ShardComServer(int port) + { + _client = new UdpClient(port); + } public void Start() { diff --git a/src/NadekoBot/NadekoBot.cs b/src/NadekoBot/NadekoBot.cs index 4142aa2f..04dd0e4b 100644 --- a/src/NadekoBot/NadekoBot.cs +++ b/src/NadekoBot/NadekoBot.cs @@ -65,9 +65,9 @@ namespace NadekoBot public int ShardId { get; } public ShardsCoordinator ShardCoord { get; private set; } - private readonly ShardComClient _comClient = new ShardComClient(); + private readonly ShardComClient _comClient; - public NadekoBot(int shardId, int parentProcessId) + public NadekoBot(int shardId, int parentProcessId, int? port = null) { if (shardId < 0) throw new ArgumentOutOfRangeException(nameof(shardId)); @@ -79,6 +79,10 @@ namespace NadekoBot TerribleElevatedPermissionCheck(); Credentials = new BotCredentials(); + + port = port ?? Credentials.ShardRunPort; + _comClient = new ShardComClient(port.Value); + Db = new DbService(Credentials); using (var uow = Db.UnitOfWork) @@ -108,7 +112,7 @@ namespace NadekoBot Currency = new CurrencyService(BotConfig, Db); GoogleApi = new GoogleApiService(Credentials); - SetupShard(shardId, parentProcessId); + SetupShard(shardId, parentProcessId, port.Value); #if GLOBAL_NADEKO Client.Log += Client_Log; @@ -411,7 +415,7 @@ namespace NadekoBot } } - private void SetupShard(int shardId, int parentProcessId) + private void SetupShard(int shardId, int parentProcessId, int port) { if (shardId != 0) { @@ -432,7 +436,7 @@ namespace NadekoBot } else { - ShardCoord = new ShardsCoordinator(); + ShardCoord = new ShardsCoordinator(port); } } } diff --git a/src/NadekoBot/Program.cs b/src/NadekoBot/Program.cs index a45affcc..09e53142 100644 --- a/src/NadekoBot/Program.cs +++ b/src/NadekoBot/Program.cs @@ -4,8 +4,13 @@ { public static void Main(string[] args) { - if (args.Length == 2 && int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId)) - new NadekoBot(shardId, parentProcessId).RunAndBlockAsync(args).GetAwaiter().GetResult(); + if (args.Length == 3 && int.TryParse(args[0], out int shardId) && int.TryParse(args[1], out int parentProcessId)) + { + int? port = null; + if (int.TryParse(args[2], out var outPort)) + port = outPort; + new NadekoBot(shardId, parentProcessId, outPort).RunAndBlockAsync(args).GetAwaiter().GetResult(); + } else new NadekoBot(0, 0).RunAndBlockAsync(args).GetAwaiter().GetResult(); } diff --git a/src/NadekoBot/Services/Impl/BotCredentials.cs b/src/NadekoBot/Services/Impl/BotCredentials.cs index b54bed23..3d47a207 100644 --- a/src/NadekoBot/Services/Impl/BotCredentials.cs +++ b/src/NadekoBot/Services/Impl/BotCredentials.cs @@ -34,6 +34,7 @@ namespace NadekoBot.Services.Impl public string PatreonAccessToken { get; } public string ShardRunCommand { get; } public string ShardRunArguments { get; } + public int ShardRunPort { get; } public BotCredentials() { @@ -65,11 +66,16 @@ namespace NadekoBot.Services.Impl PatreonAccessToken = data[nameof(PatreonAccessToken)]; ShardRunCommand = data[nameof(ShardRunCommand)]; ShardRunArguments = data[nameof(ShardRunArguments)]; - if (string.IsNullOrWhiteSpace(ShardRunCommand)) ShardRunCommand = "dotnet"; if (string.IsNullOrWhiteSpace(ShardRunArguments)) - ShardRunArguments = "run -c Release -- {0} {1}"; + ShardRunArguments = "run -c Release -- {0} {1} {2}"; + + var portStr = data[nameof(ShardRunPort)]; + if (string.IsNullOrWhiteSpace(portStr)) + ShardRunPort = new NadekoRandom().Next(5000, 6000); + else + ShardRunPort = int.Parse(portStr); int ts = 1; int.TryParse(data[nameof(TotalShards)], out ts); @@ -115,7 +121,10 @@ namespace NadekoBot.Services.Impl public DBConfig Db { get; set; } = new DBConfig("sqlite", "Filename=./data/NadekoBot.db"); public int TotalShards { get; set; } = 1; public string PatreonAccessToken { get; set; } = ""; + public string ShardRunCommand { get; set; } = ""; + public string ShardRunArguments { get; set; } = ""; + public int? ShardRunPort { get; set; } = null; } private class DbModel diff --git a/src/NadekoBot/Services/Impl/StatsService.cs b/src/NadekoBot/Services/Impl/StatsService.cs index 64507106..07d706e1 100644 --- a/src/NadekoBot/Services/Impl/StatsService.cs +++ b/src/NadekoBot/Services/Impl/StatsService.cs @@ -17,7 +17,7 @@ namespace NadekoBot.Services.Impl private readonly IBotCredentials _creds; private readonly DateTime _started; - public const string BotVersion = "1.43"; + public const string BotVersion = "1.5"; public string Author => "Kwoth#2560"; public string Library => "Discord.Net"; diff --git a/src/NadekoBot/ShardsCoordinator.cs b/src/NadekoBot/ShardsCoordinator.cs index fcf80ebe..18725566 100644 --- a/src/NadekoBot/ShardsCoordinator.cs +++ b/src/NadekoBot/ShardsCoordinator.cs @@ -20,16 +20,18 @@ namespace NadekoBot private readonly Logger _log; private readonly ShardComServer _comServer; + private readonly int _port; - public ShardsCoordinator() + public ShardsCoordinator(int port) { LogSetup.SetupLogger(); Credentials = new BotCredentials(); ShardProcesses = new Process[Credentials.TotalShards]; Statuses = new ShardComMessage[Credentials.TotalShards]; _log = LogManager.GetCurrentClassLogger(); + _port = port; - _comServer = new ShardComServer(); + _comServer = new ShardComServer(port); _comServer.Start(); _comServer.OnDataReceived += _comServer_OnDataReceived; @@ -51,7 +53,7 @@ namespace NadekoBot var p = Process.Start(new ProcessStartInfo() { FileName = Credentials.ShardRunCommand, - Arguments = string.Format(Credentials.ShardRunArguments, i, curProcessId) + Arguments = string.Format(Credentials.ShardRunArguments, i, curProcessId, _port) }); await Task.Delay(5000); } diff --git a/src/NadekoBot/credentials_example.json b/src/NadekoBot/credentials_example.json index 7c7e4095..8f977d87 100644 --- a/src/NadekoBot/credentials_example.json +++ b/src/NadekoBot/credentials_example.json @@ -16,5 +16,7 @@ }, "TotalShards": 1, "PatreonAccessToken": "", - "ShardRunCommand": "" + "ShardRunCommand": "", + "ShardRunArguments": "", + "ShardRunPort": null } \ No newline at end of file From e75f23557bcbab094f9e9ac257990b1c0ab3baa6 Mon Sep 17 00:00:00 2001 From: Master Kwoth Date: Sun, 25 Jun 2017 06:18:23 +0200 Subject: [PATCH 26/26] Small addition to docs --- docs/JSON Explanations.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/JSON Explanations.md b/docs/JSON Explanations.md index bf84432d..d83e97b3 100644 --- a/docs/JSON Explanations.md +++ b/docs/JSON Explanations.md @@ -145,10 +145,12 @@ It should look like: - Required if the bot will be connected to more than 1500 servers. - Most likely unnecessary to change until your bot is added to more than 1500 servers. - **ShardRunCommand** - - Required if you're sharding your bot on windows using .exe, or in a custom way. + - Command with which to run shards 1+ + - Required if you're sharding your bot on windows using .exe, or in a custom way. - This internally defaults to `dotnet` - For example, if you want to shard your NadekoBot which you installed using windows installer, you would want to set it to something like this: `C:\Program Files\NadekoBot\system\NadekoBot.exe` - **ShardRunArguments** + - Arguments to the shard run command - Required if you're sharding your bot on windows using .exe, or in a custom way. - This internally defaults to `run -c Release -- {0} {1} {2}` which will be enough to run linux and other 'from source' setups - {0} will be replaced by the `shard ID` of the shard being ran, {1} by the shard 0's process id, and {2} by the port shard communication is happening on