Huge changes to make shards run in separate processes

This commit is contained in:
Master Kwoth 2017-06-19 15:42:10 +02:00
parent abd2937708
commit b381ee00b6
73 changed files with 586 additions and 331 deletions

View File

@ -13,6 +13,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
/// Try to execute some logic within some module's service. /// Try to execute some logic within some module's service.
/// </summary> /// </summary>
/// <returns>Whether it should block other command executions after it.</returns> /// <returns>Whether it should block other command executions after it.</returns>
Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg); Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg);
} }
} }

View File

@ -6,7 +6,7 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
{ {
public interface ILateBlocker public interface ILateBlocker
{ {
Task<bool> TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, Task<bool> TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild,
IMessageChannel channel, IUser user, string moduleName, string commandName); IMessageChannel channel, IUser user, string moduleName, string commandName);
} }
} }

View File

@ -9,6 +9,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
/// </summary> /// </summary>
public interface ILateExecutor public interface ILateExecutor
{ {
Task LateExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg); Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg);
} }
} }

View File

@ -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; }
}
}

View File

@ -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);
}
}
}
}

View File

@ -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<ShardComMessage>(data));
}
});
}
public void Dispose()
{
_client.Dispose();
}
public event Func<ShardComMessage, Task> OnDataReceived = delegate { return Task.CompletedTask; };
}
}

View File

@ -7,9 +7,9 @@ namespace NadekoBot.TypeReaders
{ {
public class GuildTypeReader : TypeReader public class GuildTypeReader : TypeReader
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public GuildTypeReader(DiscordShardedClient client) public GuildTypeReader(DiscordSocketClient client)
{ {
_client = client; _client = client;
} }

View File

@ -140,7 +140,7 @@ namespace NadekoBot.Modules.Administration
await uow.CompleteAsync(); await uow.CompleteAsync();
} }
await Context.Channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client, page, (curPage) => await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page, (curPage) =>
{ {
return new EmbedBuilder() return new EmbedBuilder()
.WithTitle(GetText("self_assign_list", roleCnt)) .WithTitle(GetText("self_assign_list", roleCnt))

View File

@ -13,6 +13,7 @@ using NadekoBot.Services;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using NadekoBot.Services.Administration; using NadekoBot.Services.Administration;
using System.Diagnostics;
namespace NadekoBot.Modules.Administration namespace NadekoBot.Modules.Administration
{ {
@ -25,10 +26,10 @@ namespace NadekoBot.Modules.Administration
private static readonly object _locker = new object(); private static readonly object _locker = new object();
private readonly SelfService _service; private readonly SelfService _service;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly IImagesService _images; private readonly IImagesService _images;
public SelfCommands(DbService db, SelfService service, DiscordShardedClient client, public SelfCommands(DbService db, SelfService service, DiscordSocketClient client,
IImagesService images) IImagesService images)
{ {
_db = db; _db = db;
@ -204,28 +205,29 @@ namespace NadekoBot.Modules.Administration
} }
[NadekoCommand, Usage, Description, Aliases] //todo 2 shard commands
[OwnerOnly] //[NadekoCommand, Usage, Description, Aliases]
public async Task ConnectShard(int shardid) //[OwnerOnly]
{ //public async Task ConnectShard(int shardid)
var shard = _client.GetShard(shardid); //{
// var shard = _client.GetShard(shardid);
if (shard == null) // if (shard == null)
{ // {
await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false); // await ReplyErrorLocalized("no_shard_id").ConfigureAwait(false);
return; // return;
} // }
try // try
{ // {
await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false); // await ReplyConfirmLocalized("shard_reconnecting", Format.Bold("#" + shardid)).ConfigureAwait(false);
await shard.StartAsync().ConfigureAwait(false); // await shard.StartAsync().ConfigureAwait(false);
await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false); // await ReplyConfirmLocalized("shard_reconnected", Format.Bold("#" + shardid)).ConfigureAwait(false);
} // }
catch (Exception ex) // catch (Exception ex)
{ // {
_log.Warn(ex); // _log.Warn(ex);
} // }
} //}
[NadekoCommand, Usage, Description, Aliases] [NadekoCommand, Usage, Description, Aliases]
[OwnerOnly] [OwnerOnly]
@ -417,8 +419,10 @@ namespace NadekoBot.Modules.Administration
[OwnerOnly] [OwnerOnly]
public async Task ReloadImages() public async Task ReloadImages()
{ {
var time = _images.Reload(); var sw = Stopwatch.StartNew();
await ReplyConfirmLocalized("images_loaded", time.TotalSeconds.ToString("F3")).ConfigureAwait(false); _images.Reload();
sw.Stop();
await ReplyConfirmLocalized("images_loaded", sw.Elapsed.TotalSeconds.ToString("F3")).ConfigureAwait(false);
} }
private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus) private static UserStatus SettableUserStatusToUserStatus(SettableUserStatus sus)

View File

@ -36,7 +36,7 @@ namespace NadekoBot.Modules.Administration
.ToArray(); .ToArray();
var timezonesPerPage = 20; var timezonesPerPage = 20;
await Context.Channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client, page, await Context.Channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client, page,
(curPage) => new EmbedBuilder() (curPage) => new EmbedBuilder()
.WithOkColor() .WithOkColor()
.WithTitle(GetText("timezones_available")) .WithTitle(GetText("timezones_available"))

View File

@ -17,10 +17,10 @@ namespace NadekoBot.Modules.CustomReactions
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly DbService _db; private readonly DbService _db;
private readonly CustomReactionsService _crs; private readonly CustomReactionsService _crs;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public CustomReactions(IBotCredentials creds, DbService db, CustomReactionsService crs, public CustomReactions(IBotCredentials creds, DbService db, CustomReactionsService crs,
DiscordShardedClient client) DiscordSocketClient client)
{ {
_creds = creds; _creds = creds;
_db = db; _db = db;

View File

@ -22,12 +22,12 @@ namespace NadekoBot.Modules.Gambling
{ {
private readonly BotConfig _bc; private readonly BotConfig _bc;
private readonly CurrencyService _cs; private readonly CurrencyService _cs;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces { get; } = new ConcurrentDictionary<ulong, AnimalRace>(); public static ConcurrentDictionary<ulong, AnimalRace> AnimalRaces { get; } = new ConcurrentDictionary<ulong, AnimalRace>();
public AnimalRacing(BotConfig bc, CurrencyService cs, DiscordShardedClient client) public AnimalRacing(BotConfig bc, CurrencyService cs, DiscordSocketClient client)
{ {
_bc = bc; _bc = bc;
_cs = cs; _cs = cs;
@ -82,14 +82,14 @@ namespace NadekoBot.Modules.Gambling
private readonly ITextChannel _raceChannel; private readonly ITextChannel _raceChannel;
private readonly BotConfig _bc; private readonly BotConfig _bc;
private readonly CurrencyService _cs; private readonly CurrencyService _cs;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly ILocalization _localization; private readonly ILocalization _localization;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
public bool Started { get; private set; } public bool Started { get; private set; }
public AnimalRace(ulong serverId, ITextChannel channel, string prefix, BotConfig bc, public AnimalRace(ulong serverId, ITextChannel channel, string prefix, BotConfig bc,
CurrencyService cs, DiscordShardedClient client, ILocalization localization, CurrencyService cs, DiscordSocketClient client, ILocalization localization,
NadekoStrings strings) NadekoStrings strings)
{ {
_prefix = prefix; _prefix = prefix;

View File

@ -34,11 +34,11 @@ namespace NadekoBot.Modules.Gambling
.ToArray(); .ToArray();
private string _secretCode = string.Empty; private string _secretCode = string.Empty;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly BotConfig _bc; private readonly BotConfig _bc;
private readonly CurrencyService _cs; private readonly CurrencyService _cs;
public CurrencyEvents(DiscordShardedClient client, BotConfig bc, CurrencyService cs) public CurrencyEvents(DiscordSocketClient client, BotConfig bc, CurrencyService cs)
{ {
_client = client; _client = client;
_bc = bc; _bc = bc;
@ -151,7 +151,7 @@ namespace NadekoBot.Modules.Gambling
{ {
private readonly ConcurrentHashSet<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>(); private readonly ConcurrentHashSet<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>();
private readonly Logger _log; private readonly Logger _log;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly CurrencyService _cs; private readonly CurrencyService _cs;
private IUserMessage StartingMessage { get; set; } private IUserMessage StartingMessage { get; set; }
@ -159,7 +159,7 @@ namespace NadekoBot.Modules.Gambling
private CancellationTokenSource Source { get; } private CancellationTokenSource Source { get; }
private CancellationToken CancelToken { get; } private CancellationToken CancelToken { get; }
public FlowerReactionEvent(DiscordShardedClient client, CurrencyService cs) public FlowerReactionEvent(DiscordSocketClient client, CurrencyService cs)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Modules.Gambling
private readonly BotConfig _bc; private readonly BotConfig _bc;
private readonly DbService _db; private readonly DbService _db;
private readonly CurrencyService _cs; private readonly CurrencyService _cs;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public enum Role public enum Role
{ {
@ -34,7 +34,7 @@ namespace NadekoBot.Modules.Gambling
List List
} }
public FlowerShop(BotConfig bc, DbService db, CurrencyService cs, DiscordShardedClient client) public FlowerShop(BotConfig bc, DbService db, CurrencyService cs, DiscordSocketClient client)
{ {
_db = db; _db = db;
_bc = bc; _bc = bc;

View File

@ -20,12 +20,12 @@ namespace NadekoBot.Modules.Games
[Group] [Group]
public class Acropobia : NadekoSubmodule public class Acropobia : NadekoSubmodule
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
//channelId, game //channelId, game
public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>(); public static ConcurrentDictionary<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
public Acropobia(DiscordShardedClient client) public Acropobia(DiscordSocketClient client)
{ {
_client = client; _client = client;
} }
@ -86,10 +86,10 @@ namespace NadekoBot.Modules.Games
//text, votes //text, votes
private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>(); private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>();
private readonly Logger _log; private readonly Logger _log;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly NadekoStrings _strings; 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(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;

View File

@ -56,7 +56,7 @@ namespace NadekoBot.Modules.Games.Hangman
public class HangmanGame: IDisposable public class HangmanGame: IDisposable
{ {
private readonly Logger _log; private readonly Logger _log;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public IMessageChannel GameChannel { get; } public IMessageChannel GameChannel { get; }
public HashSet<char> Guesses { get; } = new HashSet<char>(); public HashSet<char> Guesses { get; } = new HashSet<char>();
@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Games.Hangman
public event Action<HangmanGame> OnEnded; public event Action<HangmanGame> OnEnded;
public HangmanGame(DiscordShardedClient client, IMessageChannel channel, string type) public HangmanGame(DiscordSocketClient client, IMessageChannel channel, string type)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;

View File

@ -15,9 +15,9 @@ namespace NadekoBot.Modules.Games
[Group] [Group]
public class HangmanCommands : NadekoSubmodule public class HangmanCommands : NadekoSubmodule
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public HangmanCommands(DiscordShardedClient client) public HangmanCommands(DiscordSocketClient client)
{ {
_client = client; _client = client;
} }

View File

@ -20,13 +20,13 @@ namespace NadekoBot.Modules.Games.Models
public bool IsActive { get; private set; } public bool IsActive { get; private set; }
private readonly Stopwatch sw; private readonly Stopwatch sw;
private readonly List<ulong> finishedUserIds; private readonly List<ulong> finishedUserIds;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly GamesService _games; private readonly GamesService _games;
private readonly string _prefix; private readonly string _prefix;
private Logger _log { get; } 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(); _log = LogManager.GetCurrentClassLogger();
_games = games; _games = games;

View File

@ -13,10 +13,10 @@ namespace NadekoBot.Modules.Games
[Group] [Group]
public class PollCommands : NadekoSubmodule public class PollCommands : NadekoSubmodule
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly PollService _polls; private readonly PollService _polls;
public PollCommands(DiscordShardedClient client, PollService polls) public PollCommands(DiscordSocketClient client, PollService polls)
{ {
_client = client; _client = client;
_polls = polls; _polls = polls;

View File

@ -20,9 +20,9 @@ namespace NadekoBot.Modules.Games
{ {
public static ConcurrentDictionary<ulong, TypingGame> RunningContests = new ConcurrentDictionary<ulong, TypingGame>(); public static ConcurrentDictionary<ulong, TypingGame> RunningContests = new ConcurrentDictionary<ulong, TypingGame>();
private readonly GamesService _games; 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; _games = games;
_client = client; _client = client;

View File

@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Games
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>(); private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
private readonly SemaphoreSlim _sem = new SemaphoreSlim(1, 1); 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; _client = client;
} }
@ -87,9 +87,9 @@ namespace NadekoBot.Modules.Games
private IUserMessage _previousMessage; private IUserMessage _previousMessage;
private Timer _timeoutTimer; private Timer _timeoutTimer;
private readonly NadekoStrings _strings; 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; _channel = channel;
_strings = strings; _strings = strings;

View File

@ -20,7 +20,7 @@ namespace NadekoBot.Modules.Games.Trivia
private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1); private readonly SemaphoreSlim _guessLock = new SemaphoreSlim(1, 1);
private readonly Logger _log; private readonly Logger _log;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly BotConfig _bc; private readonly BotConfig _bc;
private readonly CurrencyService _cs; private readonly CurrencyService _cs;
@ -43,7 +43,7 @@ namespace NadekoBot.Modules.Games.Trivia
public int WinRequirement { get; } 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, CurrencyService cs, IGuild guild, ITextChannel channel,
bool showHints, int winReq, bool isPokemon) bool showHints, int winReq, bool isPokemon)
{ {

View File

@ -18,12 +18,12 @@ namespace NadekoBot.Modules.Games
public class TriviaCommands : NadekoSubmodule public class TriviaCommands : NadekoSubmodule
{ {
private readonly CurrencyService _cs; private readonly CurrencyService _cs;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly BotConfig _bc; private readonly BotConfig _bc;
public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>(); public static ConcurrentDictionary<ulong, TriviaGame> RunningTrivias { get; } = new ConcurrentDictionary<ulong, TriviaGame>();
public TriviaCommands(DiscordShardedClient client, BotConfig bc, CurrencyService cs) public TriviaCommands(DiscordSocketClient client, BotConfig bc, CurrencyService cs)
{ {
_cs = cs; _cs = cs;
_client = client; _client = client;

View File

@ -22,12 +22,12 @@ namespace NadekoBot.Modules.Music
public class Music : NadekoTopLevelModule public class Music : NadekoTopLevelModule
{ {
private static MusicService _music; private static MusicService _music;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly IGoogleApiService _google; private readonly IGoogleApiService _google;
private readonly DbService _db; private readonly DbService _db;
public Music(DiscordShardedClient client, IBotCredentials creds, IGoogleApiService google, public Music(DiscordSocketClient client, IBotCredentials creds, IGoogleApiService google,
DbService db, MusicService music) DbService db, MusicService music)
{ {
_client = client; _client = client;

View File

@ -86,13 +86,12 @@ namespace NadekoBot.Modules
var text = GetText(textKey, replacements); var text = GetText(textKey, replacements);
return Context.Channel.SendConfirmAsync(Context.User.Mention + " " + text); 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<string> GetUserInputAsync(ulong userId, ulong channelId) public async Task<string> GetUserInputAsync(ulong userId, ulong channelId)
{ {
var userInputTask = new TaskCompletionSource<string>(); var userInputTask = new TaskCompletionSource<string>();
var dsc = (DiscordShardedClient)Context.Client; var dsc = (DiscordSocketClient)Context.Client;
try try
{ {
dsc.MessageReceived += MessageReceived; dsc.MessageReceived += MessageReceived;

View File

@ -195,7 +195,7 @@ namespace NadekoBot.Modules.Permissions
var fws = fwHash.ToArray(); var fws = fwHash.ToArray();
await channel.SendPaginatedConfirmAsync((DiscordShardedClient)Context.Client, await channel.SendPaginatedConfirmAsync((DiscordSocketClient)Context.Client,
page, page,
(curPage) => (curPage) =>
new EmbedBuilder() new EmbedBuilder()

View File

@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Utility
{ {
private readonly CommandMapService _service; private readonly CommandMapService _service;
private readonly DbService _db; 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; _service = service;
_db = db; _db = db;

View File

@ -16,10 +16,10 @@ namespace NadekoBot.Modules.Utility
[Group] [Group]
public class InfoCommands : NadekoSubmodule public class InfoCommands : NadekoSubmodule
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly IStatsService _stats; private readonly IStatsService _stats;
public InfoCommands(DiscordShardedClient client, IStatsService stats, CommandHandler ch) public InfoCommands(DiscordSocketClient client, IStatsService stats, CommandHandler ch)
{ {
_client = client; _client = client;
_stats = stats; _stats = stats;

View File

@ -22,10 +22,10 @@ namespace NadekoBot.Modules.Utility
public class RepeatCommands : NadekoSubmodule public class RepeatCommands : NadekoSubmodule
{ {
private readonly MessageRepeaterService _service; private readonly MessageRepeaterService _service;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly DbService _db; private readonly DbService _db;
public RepeatCommands(MessageRepeaterService service, DiscordShardedClient client, DbService db) public RepeatCommands(MessageRepeaterService service, DiscordSocketClient client, DbService db)
{ {
_service = service; _service = service;
_client = client; _client = client;

View File

@ -24,15 +24,17 @@ namespace NadekoBot.Modules.Utility
public partial class Utility : NadekoTopLevelModule public partial class Utility : NadekoTopLevelModule
{ {
private static ConcurrentDictionary<ulong, Timer> _rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>(); private static ConcurrentDictionary<ulong, Timer> _rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly IStatsService _stats; private readonly IStatsService _stats;
private readonly IBotCredentials _creds; 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; _client = client;
_stats = stats; _stats = stats;
_creds = creds; _creds = creds;
_bot = bot;
} }
//[NadekoCommand, Usage, Description, Aliases] //[NadekoCommand, Usage, Description, Aliases]
@ -352,56 +354,56 @@ namespace NadekoBot.Modules.Utility
await Context.Channel.SendConfirmAsync($"{Context.User.Mention} https://discord.gg/{invite.Code}"); 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] // var status = string.Join(", ", _client.Shards.GroupBy(x => x.ConnectionState)
public async Task ShardStats(int page = 1) // .Select(x => $"{x.Count()} {x.Key}")
{ // .ToArray());
if (--page < 0)
return;
var status = string.Join(", ", _client.Shards.GroupBy(x => x.ConnectionState) // var allShardStrings = _client.Shards
.Select(x => $"{x.Count()} {x.Key}") // .Select(x =>
.ToArray()); // GetText("shard_stats_txt", x.ShardId.ToString(),
// Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString())))
var allShardStrings = _client.Shards // .ToArray();
.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)) // if (string.IsNullOrWhiteSpace(str))
str = GetText("no_shards_on_page"); // str = GetText("no_shards_on_page");
return new EmbedBuilder() // return new EmbedBuilder()
.WithAuthor(a => a.WithName(GetText("shard_stats"))) // .WithAuthor(a => a.WithName(GetText("shard_stats")))
.WithTitle(status) // .WithTitle(status)
.WithOkColor() // .WithOkColor()
.WithDescription(str); // .WithDescription(str);
}, allShardStrings.Length / 25); // }, allShardStrings.Length / 25);
} //}
[NadekoCommand, Usage, Description, Aliases] //[NadekoCommand, Usage, Description, Aliases]
public async Task ShardId(IGuild guild) //public async Task ShardId(IGuild guild)
{ //{
var shardId = _client.GetShardIdFor(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] [NadekoCommand, Usage, Description, Aliases]
public async Task Stats() public async Task Stats()
{ {
var shardId = Context.Guild != null //var shardId = Context.Guild != null
? _client.GetShardIdFor(Context.Guild) // ? _client.GetShardIdFor(Context.Guild)
: 0; // : 0;
await Context.Channel.EmbedAsync( await Context.Channel.EmbedAsync(
new EmbedBuilder().WithOkColor() new EmbedBuilder().WithOkColor()
.WithAuthor(eab => eab.WithName($"NadekoBot v{StatsService.BotVersion}") .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")) .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("author")).WithValue(_stats.Author).WithIsInline(true))
.AddField(efb => efb.WithName(GetText("botid")).WithValue(_client.CurrentUser.Id.ToString()).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("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("messages")).WithValue($"{_stats.MessageCounter} ({_stats.MessagesPerSecond:F2}/sec)").WithIsInline(true))
.AddField(efb => efb.WithName(GetText("memory")).WithValue($"{_stats.Heap} MB").WithIsInline(true)) .AddField(efb => efb.WithName(GetText("memory")).WithValue($"{_stats.Heap} MB").WithIsInline(true))

View File

@ -27,8 +27,7 @@ using NadekoBot.Services.Utility;
using NadekoBot.Services.Help; using NadekoBot.Services.Help;
using System.IO; using System.IO;
using NadekoBot.Services.Pokemon; using NadekoBot.Services.Pokemon;
using NadekoBot.DataStructures; using NadekoBot.DataStructures.ShardCom;
using NadekoBot.Extensions;
namespace NadekoBot namespace NadekoBot
{ {
@ -45,47 +44,74 @@ namespace NadekoBot
public static Color OkColor { get; private set; } public static Color OkColor { get; private set; }
public static Color ErrorColor { get; private set; } public static Color ErrorColor { get; private set; }
public ImmutableArray<GuildConfig> AllGuildConfigs { get; } public ImmutableArray<GuildConfig> AllGuildConfigs { get; private set; }
public BotConfig BotConfig { get; } public BotConfig BotConfig { get; }
public DbService Db { get; } public DbService Db { get; }
public CommandService CommandService { get; } public CommandService CommandService { get; }
public CommandHandler CommandHandler { get; private set; } public CommandHandler CommandHandler { get; private set; }
public Localization Localization { get; } public Localization Localization { get; private set; }
public NadekoStrings Strings { get; } public NadekoStrings Strings { get; private set; }
public StatsService Stats { get; } public StatsService Stats { get; private set; }
public ImagesService Images { get; } public ImagesService Images { get; }
public CurrencyService Currency { get; } public CurrencyService Currency { get; }
public GoogleApiService GoogleApi { get; } public GoogleApiService GoogleApi { get; }
public DiscordShardedClient Client { get; } public DiscordSocketClient Client { get; }
public bool Ready { get; private set; } public bool Ready { get; private set; }
public INServiceProvider Services { get; private set; } public INServiceProvider Services { get; private set; }
public BotCredentials Credentials { get; } 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(); _log = LogManager.GetCurrentClassLogger();
TerribleElevatedPermissionCheck(); 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(); Credentials = new BotCredentials();
Db = new DbService(Credentials); Db = new DbService(Credentials);
using (var uow = Db.UnitOfWork) using (var uow = Db.UnitOfWork)
{ {
AllGuildConfigs = uow.GuildConfigs.GetAllGuildConfigs().ToImmutableArray();
BotConfig = uow.BotConfig.GetOrCreate(); BotConfig = uow.BotConfig.GetOrCreate();
OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16)); OkColor = new Color(Convert.ToUInt32(BotConfig.OkColor, 16));
ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16)); ErrorColor = new Color(Convert.ToUInt32(BotConfig.ErrorColor, 16));
} }
Client = new DiscordShardedClient(new DiscordSocketConfig Client = new DiscordSocketClient(new DiscordSocketConfig
{ {
MessageCacheSize = 10, MessageCacheSize = 10,
LogLevel = LogSeverity.Warning, LogLevel = LogSeverity.Warning,
TotalShards = Credentials.TotalShards,
ConnectionTimeout = int.MaxValue, ConnectionTimeout = int.MaxValue,
TotalShards = Credentials.TotalShards,
ShardId = shardId,
AlwaysDownloadUsers = false, AlwaysDownloadUsers = false,
}); });
@ -96,21 +122,45 @@ namespace NadekoBot
}); });
//foundation services //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(); Images = new ImagesService();
Currency = new CurrencyService(BotConfig, Db); Currency = new CurrencyService(BotConfig, Db);
GoogleApi = new GoogleApiService(Credentials); GoogleApi = new GoogleApiService(Credentials);
StartSendingData();
#if GLOBAL_NADEKO #if GLOBAL_NADEKO
Client.Log += Client_Log; Client.Log += Client_Log;
#endif #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() 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); var soundcloudApiService = new SoundCloudApiService(Credentials);
#region help #region help
@ -185,7 +235,7 @@ namespace NadekoBot
.Add<IBotCredentials>(Credentials) .Add<IBotCredentials>(Credentials)
.Add<CommandService>(CommandService) .Add<CommandService>(CommandService)
.Add<NadekoStrings>(Strings) .Add<NadekoStrings>(Strings)
.Add<DiscordShardedClient>(Client) .Add<DiscordSocketClient>(Client)
.Add<BotConfig>(BotConfig) .Add<BotConfig>(BotConfig)
.Add<CurrencyService>(Currency) .Add<CurrencyService>(Currency)
.Add<CommandHandler>(CommandHandler) .Add<CommandHandler>(CommandHandler)
@ -242,19 +292,30 @@ namespace NadekoBot
CommandService.AddTypeReader<GuildDateTime>(new GuildDateTimeTypeReader(guildTimezoneService)); CommandService.AddTypeReader<GuildDateTime>(new GuildDateTimeTypeReader(guildTimezoneService));
} }
private async Task LoginAsync(string token) private Task LoginAsync(string token)
{ {
_log.Info("Logging in...");
//connect //connect
await Client.LoginAsync(TokenType.Bot, token).ConfigureAwait(false); try { sem.WaitOne(); } catch (AbandonedMutexException) { }
await Client.StartAsync().ConfigureAwait(false); _log.Info("Shard {0} logging in ...", ShardId);
try
_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); Client.LoginAsync(TokenType.Bot, token).GetAwaiter().GetResult();
await Task.Delay(1000).ConfigureAwait(false); 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) public async Task RunAsync(params string[] args)
@ -265,11 +326,11 @@ namespace NadekoBot
await LoginAsync(Credentials.Token).ConfigureAwait(false); await LoginAsync(Credentials.Token).ConfigureAwait(false);
_log.Info("Loading services..."); _log.Info($"Shard {ShardId} loading services...");
AddServices(); AddServices();
sw.Stop(); 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<IStatsService>(); var stats = Services.GetService<IStatsService>();
stats.Initialize(); stats.Initialize();
@ -298,7 +359,8 @@ namespace NadekoBot
.ForEach(x => CommandService.RemoveModuleAsync(x)); .ForEach(x => CommandService.RemoveModuleAsync(x));
#endif #endif
Ready = true; 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) private Task Client_Log(LogMessage arg)
@ -330,19 +392,5 @@ namespace NadekoBot
Environment.Exit(2); 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;
}
} }
} }

View File

@ -2,7 +2,14 @@
{ {
public class Program public class Program
{ {
public static void Main(string[] args) => public static void Main(string[] args)
new NadekoBot().RunAndBlockAsync(args).GetAwaiter().GetResult(); {
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();
}
} }
} }

View File

@ -0,0 +1,8 @@
{
"profiles": {
"NadekoBot": {
"commandName": "Project",
"commandLineArgs": "main"
}
}
}

View File

@ -12,12 +12,12 @@ namespace NadekoBot.Services.Administration
public class AutoAssignRoleService public class AutoAssignRoleService
{ {
private readonly Logger _log; private readonly Logger _log;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
//guildid/roleid //guildid/roleid
public ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; } public ConcurrentDictionary<ulong, ulong> AutoAssignedRoles { get; }
public AutoAssignRoleService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs) public AutoAssignRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;

View File

@ -16,9 +16,9 @@ namespace NadekoBot.Services.Administration
private readonly Logger _log; private readonly Logger _log;
private readonly DbService _db; private readonly DbService _db;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public GameVoiceChannelService(DiscordShardedClient client, DbService db, IEnumerable<GuildConfig> gcs) public GameVoiceChannelService(DiscordSocketClient client, DbService db, IEnumerable<GuildConfig> gcs)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_db = db; _db = db;

View File

@ -16,7 +16,7 @@ namespace NadekoBot.Services.Administration
public class LogCommandService public class LogCommandService
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly Logger _log; private readonly Logger _log;
private string PrettyCurrentTime => $"【{DateTime.UtcNow:HH:mm:ss}】"; private string PrettyCurrentTime => $"【{DateTime.UtcNow:HH:mm:ss}】";
@ -31,7 +31,7 @@ namespace NadekoBot.Services.Administration
private readonly MuteService _mute; private readonly MuteService _mute;
private readonly ProtectionService _prot; private readonly ProtectionService _prot;
public LogCommandService(DiscordShardedClient client, NadekoStrings strings, public LogCommandService(DiscordSocketClient client, NadekoStrings strings,
IEnumerable<GuildConfig> gcs, DbService db, MuteService mute, ProtectionService prot) IEnumerable<GuildConfig> gcs, DbService db, MuteService mute, ProtectionService prot)
{ {
_client = client; _client = client;
@ -74,7 +74,7 @@ namespace NadekoBot.Services.Administration
_client.UserUnbanned += _client_UserUnbanned; _client.UserUnbanned += _client_UserUnbanned;
_client.UserJoined += _client_UserJoined; _client.UserJoined += _client_UserJoined;
_client.UserLeft += _client_UserLeft; _client.UserLeft += _client_UserLeft;
_client.UserPresenceUpdated += _client_UserPresenceUpdated; //_client.UserPresenceUpdated += _client_UserPresenceUpdated;
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated; _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated;
_client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS; _client.UserVoiceStateUpdated += _client_UserVoiceStateUpdated_TTS;
_client.GuildMemberUpdated += _client_GuildUserUpdated; _client.GuildMemberUpdated += _client_GuildUserUpdated;
@ -576,48 +576,48 @@ namespace NadekoBot.Services.Administration
return Task.CompletedTask; return Task.CompletedTask;
} }
private Task _client_UserPresenceUpdated(Optional<SocketGuild> optGuild, SocketUser usr, SocketPresence before, SocketPresence after) //private Task _client_UserPresenceUpdated(Optional<SocketGuild> optGuild, SocketUser usr, SocketPresence before, SocketPresence after)
{ //{
var _ = Task.Run(async () => // var _ = Task.Run(async () =>
{ // {
try // try
{ // {
var guild = optGuild.GetValueOrDefault() ?? (usr as SocketGuildUser)?.Guild; // var guild = optGuild.GetValueOrDefault() ?? (usr as SocketGuildUser)?.Guild;
if (guild == null) // if (guild == null)
return; // return;
if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting) // if (!GuildLogSettings.TryGetValue(guild.Id, out LogSetting logSetting)
|| (logSetting.LogUserPresenceId == null) // || (logSetting.LogUserPresenceId == null)
|| before.Status == after.Status) // || before.Status == after.Status)
return; // return;
ITextChannel logChannel; // ITextChannel logChannel;
if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserPresence)) == null) // if ((logChannel = await TryGetLogChannel(guild, logSetting, LogType.UserPresence)) == null)
return; // return;
string str = ""; // string str = "";
if (before.Status != after.Status) // if (before.Status != after.Status)
str = "🎭" + Format.Code(PrettyCurrentTime) + // str = "🎭" + Format.Code(PrettyCurrentTime) +
GetText(logChannel.Guild, "user_status_change", // GetText(logChannel.Guild, "user_status_change",
"👤" + Format.Bold(usr.Username), // "👤" + Format.Bold(usr.Username),
Format.Bold(after.Status.ToString())); // Format.Bold(after.Status.ToString()));
//if (before.Game?.Name != after.Game?.Name) // //if (before.Game?.Name != after.Game?.Name)
//{ // //{
// if (str != "") // // if (str != "")
// str += "\n"; // // str += "\n";
// str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**."; // // str += $"👾`{prettyCurrentTime}`👤__**{usr.Username}**__ is now playing **{after.Game?.Name}**.";
//} // //}
PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; }); // PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
} // }
catch // catch
{ // {
// ignored // // ignored
} // }
}); // });
return Task.CompletedTask; // return Task.CompletedTask;
} //}
private Task _client_UserLeft(IGuildUser usr) private Task _client_UserLeft(IGuildUser usr)
{ {

View File

@ -33,10 +33,10 @@ namespace NadekoBot.Services.Administration
private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny); private static readonly OverwritePermissions denyOverwrite = new OverwritePermissions(sendMessages: PermValue.Deny, attachFiles: PermValue.Deny);
private readonly Logger _log = LogManager.GetCurrentClassLogger(); private readonly Logger _log = LogManager.GetCurrentClassLogger();
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly DbService _db; private readonly DbService _db;
public MuteService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, DbService db) public MuteService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
{ {
_client = client; _client = client;
_db = db; _db = db;

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Services.Administration
public List<PlayingStatus> RotatingStatusMessages { get; } public List<PlayingStatus> RotatingStatusMessages { get; }
public volatile bool RotatingStatuses; public volatile bool RotatingStatuses;
private readonly Timer _t; private readonly Timer _t;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly BotConfig _bc; private readonly BotConfig _bc;
private readonly MusicService _music; private readonly MusicService _music;
private readonly Logger _log; private readonly Logger _log;
@ -27,7 +27,7 @@ namespace NadekoBot.Services.Administration
public int Index { get; set; } public int Index { get; set; }
} }
public PlayingRotateService(DiscordShardedClient client, BotConfig bc, MusicService music) public PlayingRotateService(DiscordSocketClient client, BotConfig bc, MusicService music)
{ {
_client = client; _client = client;
_bc = bc; _bc = bc;
@ -36,7 +36,7 @@ namespace NadekoBot.Services.Administration
RotatingStatusMessages = _bc.RotatingStatusMessages; RotatingStatusMessages = _bc.RotatingStatusMessages;
RotatingStatuses = _bc.RotatingStatuses; RotatingStatuses = _bc.RotatingStatuses;
_t = new Timer(async (objState) => _t = new Timer(async (objState) =>
{ {
try try
@ -52,17 +52,12 @@ namespace NadekoBot.Services.Administration
var status = RotatingStatusMessages[state.Index++].Status; var status = RotatingStatusMessages[state.Index++].Status;
if (string.IsNullOrWhiteSpace(status)) if (string.IsNullOrWhiteSpace(status))
return; return;
PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(_client,_music))); PlayingPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(_client, _music)));
var shards = _client.Shards; ShardSpecificPlaceholders.ForEach(e => status = status.Replace(e.Key, e.Value(client)));
for (int i = 0; i < shards.Count; i++) try { await client.SetGameAsync(status).ConfigureAwait(false); }
catch (Exception ex)
{ {
var curShard = shards.ElementAt(i); _log.Warn(ex);
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);
}
} }
} }
catch (Exception ex) catch (Exception ex)
@ -72,8 +67,8 @@ namespace NadekoBot.Services.Administration
}, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1)); }, new TimerState(), TimeSpan.FromMinutes(1), TimeSpan.FromMinutes(1));
} }
public Dictionary<string, Func<DiscordShardedClient, MusicService, string>> PlayingPlaceholders { get; } = public Dictionary<string, Func<DiscordSocketClient, MusicService, string>> PlayingPlaceholders { get; } =
new Dictionary<string, Func<DiscordShardedClient, MusicService, string>> { new Dictionary<string, Func<DiscordSocketClient, MusicService, string>> {
{ "%servers%", (c, ms) => c.Guilds.Count.ToString()}, { "%servers%", (c, ms) => c.Guilds.Count.ToString()},
{ "%users%", (c, ms) => c.Guilds.Sum(s => s.Users.Count).ToString()}, { "%users%", (c, ms) => c.Guilds.Sum(s => s.Users.Count).ToString()},
{ "%playing%", (c, ms) => { { "%playing%", (c, ms) => {
@ -90,7 +85,6 @@ namespace NadekoBot.Services.Administration
}, },
{ "%queued%", (c, ms) => ms.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()}, { "%queued%", (c, ms) => ms.MusicPlayers.Sum(kvp => kvp.Value.Playlist.Count).ToString()},
{ "%time%", (c, ms) => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) }, { "%time%", (c, ms) => DateTime.Now.ToString("HH:mm " + TimeZoneInfo.Local.StandardName.GetInitials()) },
{ "%shardcount%", (c, ms) => c.Shards.Count.ToString() },
}; };
public Dictionary<string, Func<DiscordSocketClient, string>> ShardSpecificPlaceholders { get; } = public Dictionary<string, Func<DiscordSocketClient, string>> ShardSpecificPlaceholders { get; } =

View File

@ -21,10 +21,10 @@ namespace NadekoBot.Services.Administration
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered = delegate { return Task.CompletedTask; }; public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> OnAntiProtectionTriggered = delegate { return Task.CompletedTask; };
private readonly Logger _log; private readonly Logger _log;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly MuteService _mute; private readonly MuteService _mute;
public ProtectionService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, MuteService mute) public ProtectionService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, MuteService mute)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;

View File

@ -19,9 +19,9 @@ namespace NadekoBot.Services.Administration
public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>(); public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>();
private readonly Logger _log; private readonly Logger _log;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public SlowmodeService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs) public SlowmodeService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;

View File

@ -23,11 +23,11 @@ namespace NadekoBot.Services.Administration
private readonly Logger _log; private readonly Logger _log;
private readonly ILocalization _localization; private readonly ILocalization _localization;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels = new ImmutableArray<AsyncLazy<IDMChannel>>(); private ImmutableArray<AsyncLazy<IDMChannel>> ownerChannels = new ImmutableArray<AsyncLazy<IDMChannel>>();
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) BotConfig bc, ILocalization localization, NadekoStrings strings, IBotCredentials creds)
{ {
_bot = bot; _bot = bot;
@ -69,10 +69,7 @@ namespace NadekoBot.Services.Administration
LoadOwnerChannels(); 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<ulong>(_creds.OwnerIds); var hs = new HashSet<ulong>(_creds.OwnerIds);
var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>(); var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>();
foreach (var s in _client.Shards) if (hs.Count > 0)
{ {
if (hs.Count == 0) foreach (var g in _client.Guilds)
break;
foreach (var g in s.Guilds)
{ {
if (hs.Count == 0) if (hs.Count == 0)
break; break;
@ -101,14 +96,19 @@ namespace NadekoBot.Services.Administration
} }
} }
} }
ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key)) ownerChannels = channels.OrderBy(x => _creds.OwnerIds.IndexOf(x.Key))
.Select(x => x.Value) .Select(x => x.Value)
.ToImmutableArray(); .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 // 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) if (msg.Channel is IDMChannel && ForwardDMs && ownerChannels.Length > 0)
{ {

View File

@ -14,11 +14,11 @@ namespace NadekoBot.Services.Administration
{ {
private readonly Logger _log; private readonly Logger _log;
private readonly DbService _db; private readonly DbService _db;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; } public ConcurrentDictionary<ulong, ConcurrentDictionary<ulong, IRole>> VcRoles { get; }
public VcRoleService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, DbService db) public VcRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_db = db; _db = db;

View File

@ -20,12 +20,12 @@ namespace NadekoBot.Services.Administration
public readonly ConcurrentHashSet<ulong> VoicePlusTextCache; public readonly ConcurrentHashSet<ulong> VoicePlusTextCache;
private readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>(); private readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
private readonly DbService _db; private readonly DbService _db;
private readonly Logger _log; private readonly Logger _log;
public VplusTService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs, NadekoStrings strings, public VplusTService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, NadekoStrings strings,
DbService db) DbService db)
{ {
_client = client; _client = client;

View File

@ -17,7 +17,7 @@ namespace NadekoBot.Services.ClashOfClans
// shouldn't be here // shouldn't be here
public class ClashOfClansService public class ClashOfClansService
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly DbService _db; private readonly DbService _db;
private readonly ILocalization _localization; private readonly ILocalization _localization;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
@ -25,7 +25,7 @@ namespace NadekoBot.Services.ClashOfClans
public ConcurrentDictionary<ulong, List<ClashWar>> ClashWars { get; set; } public ConcurrentDictionary<ulong, List<ClashWar>> 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; _client = client;
_db = db; _db = db;

View File

@ -28,7 +28,7 @@ namespace NadekoBot.Services
{ {
public const int GlobalCommandsCooldown = 750; public const int GlobalCommandsCooldown = 750;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly CommandService _commandService; private readonly CommandService _commandService;
private readonly Logger _log; private readonly Logger _log;
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
@ -48,7 +48,7 @@ namespace NadekoBot.Services
public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>(); public ConcurrentHashSet<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
private readonly Timer _clearUsersOnShortCooldown; private readonly Timer _clearUsersOnShortCooldown;
public CommandHandler(DiscordShardedClient client, DbService db, BotConfig bc, IEnumerable<GuildConfig> gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot) public CommandHandler(DiscordSocketClient client, DbService db, BotConfig bc, IEnumerable<GuildConfig> gcs, CommandService commandService, IBotCredentials credentials, NadekoBot bot)
{ {
_client = client; _client = client;
_commandService = commandService; _commandService = commandService;

View File

@ -22,13 +22,13 @@ namespace NadekoBot.Services.CustomReactions
private readonly Logger _log; private readonly Logger _log;
private readonly DbService _db; private readonly DbService _db;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly PermissionService _perms; private readonly PermissionService _perms;
private readonly CommandHandler _cmd; private readonly CommandHandler _cmd;
private readonly BotConfig _bc; private readonly BotConfig _bc;
public CustomReactionsService(PermissionService perms, DbService db, public CustomReactionsService(PermissionService perms, DbService db,
DiscordShardedClient client, CommandHandler cmd, BotConfig bc) DiscordSocketClient client, CommandHandler cmd, BotConfig bc)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_db = db; _db = db;
@ -37,15 +37,12 @@ namespace NadekoBot.Services.CustomReactions
_cmd = cmd; _cmd = cmd;
_bc = bc; _bc = bc;
var sw = Stopwatch.StartNew();
using (var uow = _db.UnitOfWork) using (var uow = _db.UnitOfWork)
{ {
var items = uow.CustomReactions.GetAll(); var items = uow.CustomReactions.GetAll();
GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(items.Where(g => g.GuildId != null && g.GuildId != 0).GroupBy(k => k.GuildId.Value).ToDictionary(g => g.Key, g => g.ToArray())); GuildReactions = new ConcurrentDictionary<ulong, CustomReaction[]>(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(); 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(); public void ClearStats() => ReactionStats.Clear();
@ -98,7 +95,7 @@ namespace NadekoBot.Services.CustomReactions
return greaction; return greaction;
} }
public async Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg) public async Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg)
{ {
// maybe this message is a custom reaction // maybe this message is a custom reaction
var cr = await Task.Run(() => TryGetCustomReaction(msg)).ConfigureAwait(false); var cr = await Task.Run(() => TryGetCustomReaction(msg)).ConfigureAwait(false);

View File

@ -40,7 +40,7 @@ namespace NadekoBot.Services.CustomReactions
} }, } },
}; };
public static Dictionary<string, Func<IUserMessage, DiscordShardedClient, string>> placeholders = new Dictionary<string, Func<IUserMessage, DiscordShardedClient, string>>() public static Dictionary<string, Func<IUserMessage, DiscordSocketClient, string>> placeholders = new Dictionary<string, Func<IUserMessage, DiscordSocketClient, string>>()
{ {
{"%mention%", (ctx, client) => { return $"<@{client.CurrentUser.Id}>"; } }, {"%mention%", (ctx, client) => { return $"<@{client.CurrentUser.Id}>"; } },
{"%user%", (ctx, client) => { return ctx.Author.Mention; } }, {"%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) foreach (var ph in placeholders)
{ {
@ -104,7 +104,7 @@ namespace NadekoBot.Services.CustomReactions
return str; return str;
} }
private static async Task<string> ResolveResponseStringAsync(this string str, IUserMessage ctx, DiscordShardedClient client, string resolvedTrigger) private static async Task<string> ResolveResponseStringAsync(this string str, IUserMessage ctx, DiscordSocketClient client, string resolvedTrigger)
{ {
foreach (var ph in placeholders) foreach (var ph in placeholders)
{ {
@ -127,13 +127,13 @@ namespace NadekoBot.Services.CustomReactions
return str; 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); => cr.Trigger.ResolveTriggerString(ctx, client);
public static Task<string > ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordShardedClient client) public static Task<string > ResponseWithContextAsync(this CustomReaction cr, IUserMessage ctx, DiscordSocketClient client)
=> cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client)); => cr.Response.ResolveResponseStringAsync(ctx, client, cr.Trigger.ResolveTriggerString(ctx, client));
public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage context, DiscordShardedClient client, CustomReactionsService crs) public static async Task<IUserMessage> Send(this CustomReaction cr, IUserMessage context, DiscordSocketClient client, CustomReactionsService crs)
{ {
var channel = cr.DmResponse ? await context.Author.CreateDMChannelAsync() : context.Channel; var channel = cr.DmResponse ? await context.Author.CreateDMChannelAsync() : context.Channel;

View File

@ -11,7 +11,7 @@ namespace NadekoBot.Services.Database.Repositories
GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null); GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null);
GuildConfig LogSettingsFor(ulong guildId); GuildConfig LogSettingsFor(ulong guildId);
IEnumerable<GuildConfig> OldPermissionsForAll(); IEnumerable<GuildConfig> OldPermissionsForAll();
IEnumerable<GuildConfig> GetAllGuildConfigs(); IEnumerable<GuildConfig> GetAllGuildConfigs(List<long> availableGuilds);
IEnumerable<FollowedStream> GetAllFollowedStreams(); IEnumerable<FollowedStream> GetAllFollowedStreams();
void SetCleverbotEnabled(ulong id, bool cleverbotEnabled); void SetCleverbotEnabled(ulong id, bool cleverbotEnabled);
IEnumerable<GuildConfig> Permissionsv2ForAll(); IEnumerable<GuildConfig> Permissionsv2ForAll();

View File

@ -24,8 +24,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
} }
}; };
public IEnumerable<GuildConfig> GetAllGuildConfigs() => public IEnumerable<GuildConfig> GetAllGuildConfigs(List<long> availableGuilds) =>
_set.Include(gc => gc.LogSetting) _set
.Where(gc => availableGuilds.Contains((long)gc.GuildId))
.Include(gc => gc.LogSetting)
.ThenInclude(ls => ls.IgnoredChannels) .ThenInclude(ls => ls.IgnoredChannels)
.Include(gc => gc.MutedUsers) .Include(gc => gc.MutedUsers)
.Include(gc => gc.CommandAliases) .Include(gc => gc.CommandAliases)

View File

@ -12,7 +12,7 @@ namespace NadekoBot.Services.Discord
public event Action<SocketReaction> OnReactionRemoved = delegate { }; public event Action<SocketReaction> OnReactionRemoved = delegate { };
public event Action OnReactionsCleared = 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)); Message = msg ?? throw new ArgumentNullException(nameof(msg));
_client = client; _client = client;
@ -69,7 +69,7 @@ namespace NadekoBot.Services.Discord
} }
private bool disposing = false; private bool disposing = false;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
public void Dispose() public void Dispose()
{ {

View File

@ -15,14 +15,14 @@ namespace NadekoBot.Services.Games
{ {
public class ChatterBotService : IEarlyBlockingExecutor public class ChatterBotService : IEarlyBlockingExecutor
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly Logger _log; private readonly Logger _log;
private readonly PermissionService _perms; private readonly PermissionService _perms;
private readonly CommandHandler _cmd; private readonly CommandHandler _cmd;
public ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> ChatterBotGuilds { get; } public ConcurrentDictionary<ulong, Lazy<ChatterBotSession>> ChatterBotGuilds { get; }
public ChatterBotService(DiscordShardedClient client, PermissionService perms, IEnumerable<GuildConfig> gcs, CommandHandler cmd) public ChatterBotService(DiscordSocketClient client, PermissionService perms, IEnumerable<GuildConfig> gcs, CommandHandler cmd)
{ {
_client = client; _client = client;
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
@ -83,7 +83,7 @@ namespace NadekoBot.Services.Games
return true; return true;
} }
public async Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage usrMsg) public async Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage usrMsg)
{ {
if (!(guild is SocketGuild sg)) if (!(guild is SocketGuild sg))
return false; return false;

View File

@ -23,7 +23,7 @@ namespace NadekoBot.Services.Games
public readonly ImmutableArray<string> EightBallResponses; public readonly ImmutableArray<string> EightBallResponses;
private readonly Timer _t; private readonly Timer _t;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
private readonly IImagesService _images; private readonly IImagesService _images;
private readonly Logger _log; private readonly Logger _log;
@ -33,7 +33,7 @@ namespace NadekoBot.Services.Games
public List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>(); public List<TypingArticle> TypingArticles { get; } = new List<TypingArticle>();
public GamesService(DiscordShardedClient client, BotConfig bc, IEnumerable<GuildConfig> gcs, public GamesService(DiscordSocketClient client, BotConfig bc, IEnumerable<GuildConfig> gcs,
NadekoStrings strings, IImagesService images, CommandHandler cmdHandler) NadekoStrings strings, IImagesService images, CommandHandler cmdHandler)
{ {
_bc = bc; _bc = bc;

View File

@ -18,7 +18,7 @@ namespace NadekoBot.Services.Games
private string[] answers { get; } private string[] answers { get; }
private readonly ConcurrentDictionary<ulong, int> _participants = new ConcurrentDictionary<ulong, int>(); private readonly ConcurrentDictionary<ulong, int> _participants = new ConcurrentDictionary<ulong, int>();
private readonly string _question; private readonly string _question;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
private bool running = false; private bool running = false;
private HashSet<ulong> _guildUsers; private HashSet<ulong> _guildUsers;
@ -27,7 +27,7 @@ namespace NadekoBot.Services.Games
public bool IsPublic { get; } public bool IsPublic { get; }
public Poll(DiscordShardedClient client, NadekoStrings strings, IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false) public Poll(DiscordSocketClient client, NadekoStrings strings, IUserMessage umsg, string question, IEnumerable<string> enumerable, bool isPublic = false)
{ {
_client = client; _client = client;
_strings = strings; _strings = strings;

View File

@ -13,10 +13,10 @@ namespace NadekoBot.Services.Games
{ {
public ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>(); public ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
private readonly Logger _log; private readonly Logger _log;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
public PollService(DiscordShardedClient client, NadekoStrings strings) public PollService(DiscordSocketClient client, NadekoStrings strings)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
_client = client; _client = client;
@ -45,7 +45,7 @@ namespace NadekoBot.Services.Games
return false; return false;
} }
public async Task<bool> TryExecuteEarly(DiscordShardedClient client, IGuild guild, IUserMessage msg) public async Task<bool> TryExecuteEarly(DiscordSocketClient client, IGuild guild, IUserMessage msg)
{ {
if (guild == null) if (guild == null)
{ {

View File

@ -17,10 +17,10 @@ namespace NadekoBot.Services
private readonly DbService _db; private readonly DbService _db;
public readonly ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache; public readonly ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly Logger _log; private readonly Logger _log;
public GreetSettingsService(DiscordShardedClient client, IEnumerable<GuildConfig> guildConfigs, DbService db) public GreetSettingsService(DiscordSocketClient client, IEnumerable<GuildConfig> guildConfigs, DbService db)
{ {
_db = db; _db = db;
_client = client; _client = client;

View File

@ -24,7 +24,7 @@ namespace NadekoBot.Services.Help
_strings = strings; _strings = strings;
} }
public async Task LateExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg) public async Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg)
{ {
try try
{ {

View File

@ -20,6 +20,7 @@ namespace NadekoBot.Services
string OsuApiKey { get; } string OsuApiKey { get; }
bool IsOwner(IUser u); bool IsOwner(IUser u);
int TotalShards { get; }
} }
public class DBConfig public class DBConfig

View File

@ -18,6 +18,6 @@ namespace NadekoBot.Services
ImmutableArray<byte> WifeMatrix { get; } ImmutableArray<byte> WifeMatrix { get; }
ImmutableArray<byte> RategirlDot { get; } ImmutableArray<byte> RategirlDot { get; }
TimeSpan Reload(); void Reload();
} }
} }

View File

@ -47,12 +47,10 @@ namespace NadekoBot.Services.Impl
this.Reload(); this.Reload();
} }
public TimeSpan Reload() public void Reload()
{ {
try try
{ {
_log.Info("Loading images...");
var sw = Stopwatch.StartNew();
Heads = File.ReadAllBytes(_headsPath).ToImmutableArray(); Heads = File.ReadAllBytes(_headsPath).ToImmutableArray();
Tails = File.ReadAllBytes(_tailsPath).ToImmutableArray(); Tails = File.ReadAllBytes(_tailsPath).ToImmutableArray();
@ -79,10 +77,6 @@ namespace NadekoBot.Services.Impl
WifeMatrix = File.ReadAllBytes(_wifeMatrixPath).ToImmutableArray(); WifeMatrix = File.ReadAllBytes(_wifeMatrixPath).ToImmutableArray();
RategirlDot = File.ReadAllBytes(_rategirlDot).ToImmutableArray(); RategirlDot = File.ReadAllBytes(_rategirlDot).ToImmutableArray();
sw.Stop();
_log.Info($"Images loaded after {sw.Elapsed.TotalSeconds:F2}s!");
return sw.Elapsed;
} }
catch (Exception ex) catch (Exception ex)
{ {

View File

@ -13,7 +13,7 @@ namespace NadekoBot.Services.Impl
{ {
public class StatsService : IStatsService public class StatsService : IStatsService
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly IBotCredentials _creds; private readonly IBotCredentials _creds;
private readonly DateTime _started; private readonly DateTime _started;
@ -36,7 +36,7 @@ namespace NadekoBot.Services.Impl
private readonly Timer _carbonitexTimer; private readonly Timer _carbonitexTimer;
public StatsService(DiscordShardedClient client, CommandHandler cmdHandler, IBotCredentials creds) public StatsService(DiscordSocketClient client, CommandHandler cmdHandler, IBotCredentials creds)
{ {
_client = client; _client = client;
_creds = creds; _creds = creds;
@ -121,31 +121,32 @@ namespace NadekoBot.Services.Impl
return Task.CompletedTask; return Task.CompletedTask;
}; };
_carbonitexTimer = new Timer(async (state) => //todo carbonitex update
{ //_carbonitexTimer = new Timer(async (state) =>
if (string.IsNullOrWhiteSpace(_creds.CarbonKey)) //{
return; // if (string.IsNullOrWhiteSpace(_creds.CarbonKey))
try // return;
{ // try
using (var http = new HttpClient()) // {
{ // using (var http = new HttpClient())
using (var content = new FormUrlEncodedContent( // {
new Dictionary<string, string> { // using (var content = new FormUrlEncodedContent(
{ "servercount", _client.Guilds.Count.ToString() }, // new Dictionary<string, string> {
{ "key", _creds.CarbonKey }})) // { "servercount", _client.Guilds.Count.ToString() },
{ // { "key", _creds.CarbonKey }}))
content.Headers.Clear(); // {
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); // 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); // await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
} // }
} // }
} // }
catch // catch
{ // {
// ignored // // ignored
} // }
}, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1)); //}, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1));
} }
public void Initialize() public void Initialize()

View File

@ -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;
}
}
}

View File

@ -21,7 +21,7 @@ namespace NadekoBot.Services.Permissions
v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns))); v => new ConcurrentHashSet<CommandCooldown>(v.CommandCooldowns)));
} }
public Task<bool> TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, public Task<bool> TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild,
IMessageChannel channel, IUser user, string moduleName, string commandName) IMessageChannel channel, IUser user, string moduleName, string commandName)
{ {
if (guild == null) if (guild == null)

View File

@ -41,7 +41,7 @@ namespace NadekoBot.Services.Permissions
return words; return words;
} }
public FilterService(DiscordShardedClient _client, IEnumerable<GuildConfig> gcs) public FilterService(DiscordSocketClient _client, IEnumerable<GuildConfig> gcs)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();

View File

@ -19,7 +19,7 @@ namespace NadekoBot.Services.Permissions
BlockedCommands = new ConcurrentHashSet<string>(bc.BlockedCommands.Select(x => x.Name)); BlockedCommands = new ConcurrentHashSet<string>(bc.BlockedCommands.Select(x => x.Name));
} }
public async Task<bool> TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName) public async Task<bool> TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName)
{ {
await Task.Yield(); await Task.Yield();
commandName = commandName.ToLowerInvariant(); commandName = commandName.ToLowerInvariant();

View File

@ -1,4 +1,5 @@
using Microsoft.EntityFrameworkCore; 
using Microsoft.EntityFrameworkCore;
using NadekoBot.DataStructures.ModuleBehaviors; using NadekoBot.DataStructures.ModuleBehaviors;
using NadekoBot.Services.Database.Models; using NadekoBot.Services.Database.Models;
using NLog; using NLog;
@ -183,7 +184,7 @@ WHERE secondaryTargetName LIKE '.%' OR
}); });
} }
public async Task<bool> TryBlockLate(DiscordShardedClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName) public async Task<bool> TryBlockLate(DiscordSocketClient client, IUserMessage msg, IGuild guild, IMessageChannel channel, IUser user, string moduleName, string commandName)
{ {
await Task.Yield(); await Task.Yield();
if (guild == null) if (guild == null)

View File

@ -15,7 +15,7 @@ namespace NadekoBot.Services.Searches
{ {
public class SearchesService public class SearchesService
{ {
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly IGoogleApiService _google; private readonly IGoogleApiService _google;
private readonly DbService _db; private readonly DbService _db;
private readonly Logger _log; private readonly Logger _log;
@ -31,7 +31,7 @@ namespace NadekoBot.Services.Searches
public List<WoWJoke> WowJokes { get; } = new List<WoWJoke>(); public List<WoWJoke> WowJokes { get; } = new List<WoWJoke>();
public List<MagicItem> MagicItems { get; } = new List<MagicItem>(); public List<MagicItem> MagicItems { get; } = new List<MagicItem>();
public SearchesService(DiscordShardedClient client, IGoogleApiService google, DbService db) public SearchesService(DiscordSocketClient client, IGoogleApiService google, DbService db)
{ {
_client = client; _client = client;
_google = google; _google = google;

View File

@ -20,10 +20,10 @@ namespace NadekoBot.Services.Searches
private readonly ConcurrentDictionary<string, StreamStatus> _cachedStatuses = new ConcurrentDictionary<string, StreamStatus>(); private readonly ConcurrentDictionary<string, StreamStatus> _cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
private readonly DbService _db; private readonly DbService _db;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly NadekoStrings _strings; private readonly NadekoStrings _strings;
public StreamNotificationService(DbService db, DiscordShardedClient client, NadekoStrings strings) public StreamNotificationService(DbService db, DiscordSocketClient client, NadekoStrings strings)
{ {
_db = db; _db = db;
_client = client; _client = client;

View File

@ -15,7 +15,7 @@ namespace NadekoBot.Services.Utility
public ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; set; } public ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; set; }
public bool RepeaterReady { get; private set; } public bool RepeaterReady { get; private set; }
public MessageRepeaterService(NadekoBot bot, DiscordShardedClient client, IEnumerable<GuildConfig> gcs) public MessageRepeaterService(NadekoBot bot, DiscordSocketClient client, IEnumerable<GuildConfig> gcs)
{ {
var _ = Task.Run(async () => var _ = Task.Run(async () =>
{ {

View File

@ -30,10 +30,10 @@ namespace NadekoBot.Services.Utility
private readonly CancellationTokenSource cancelSource; private readonly CancellationTokenSource cancelSource;
private readonly CancellationToken cancelAllToken; private readonly CancellationToken cancelAllToken;
private readonly BotConfig _config; private readonly BotConfig _config;
private readonly DiscordShardedClient _client; private readonly DiscordSocketClient _client;
private readonly DbService _db; private readonly DbService _db;
public RemindService(DiscordShardedClient client, BotConfig config, DbService db) public RemindService(DiscordSocketClient client, BotConfig config, DbService db)
{ {
_config = config; _config = config;
_client = client; _client = client;

View File

@ -22,7 +22,7 @@ namespace NadekoBot.Services.Utility
private IUserMessage oldMsg = null; private IUserMessage oldMsg = null;
private Timer _t; private Timer _t;
public RepeatRunner(DiscordShardedClient client, Repeater repeater) public RepeatRunner(DiscordSocketClient client, Repeater repeater)
{ {
_log = LogManager.GetCurrentClassLogger(); _log = LogManager.GetCurrentClassLogger();
Repeater = repeater; Repeater = repeater;

View File

@ -13,9 +13,9 @@ namespace NadekoBot.Services.Utility
{ {
public readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers = public readonly ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>> Subscribers =
new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>(); new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
private DiscordShardedClient _client; private DiscordSocketClient _client;
public CrossServerTextService(IEnumerable<GuildConfig> guildConfigs, DiscordShardedClient client) public CrossServerTextService(IEnumerable<GuildConfig> guildConfigs, DiscordSocketClient client)
{ {
_client = client; _client = client;
_client.MessageReceived += Client_MessageReceived; _client.MessageReceived += Client_MessageReceived;

View File

@ -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 { }
}
}
}
}

View File

@ -70,7 +70,7 @@ namespace NadekoBot.Extensions
/// <summary> /// <summary>
/// danny kamisama /// danny kamisama
/// </summary> /// </summary>
public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordShardedClient client, int currentPage, Func<int, EmbedBuilder> pageFunc, int? lastPage = null, bool addPaginatedFooter = true) public static async Task SendPaginatedConfirmAsync(this IMessageChannel channel, DiscordSocketClient client, int currentPage, Func<int, EmbedBuilder> pageFunc, int? lastPage = null, bool addPaginatedFooter = true)
{ {
var embed = pageFunc(currentPage); var embed = pageFunc(currentPage);
@ -134,7 +134,7 @@ namespace NadekoBot.Extensions
return embed.WithFooter(efb => efb.WithText(curPage.ToString())); return embed.WithFooter(efb => efb.WithText(curPage.ToString()));
} }
public static ReactionEventWrapper OnReaction(this IUserMessage msg, DiscordShardedClient client, Action<SocketReaction> reactionAdded, Action<SocketReaction> reactionRemoved = null) public static ReactionEventWrapper OnReaction(this IUserMessage msg, DiscordSocketClient client, Action<SocketReaction> reactionAdded, Action<SocketReaction> reactionRemoved = null)
{ {
if (reactionRemoved == null) if (reactionRemoved == null)
reactionRemoved = delegate { }; reactionRemoved = delegate { };