Merge branch 'shard-process' into 1.4
This commit is contained in:
commit
61a96d9c4f
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,5 +1,6 @@
|
||||
#Manually added files
|
||||
|
||||
patreon_rewards.json
|
||||
command_errors*.txt
|
||||
|
||||
src/NadekoBot/Command Errors*.txt
|
||||
|
@ -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
|
||||
|
@ -18,7 +18,8 @@ If you do not see `credentials.json` you will need to rename `credentials_exampl
|
||||
"OsuApiKey": "4c8c8fdff8e1234581725db27fd140a7d93320d6",
|
||||
"PatreonAccessToken": "",
|
||||
"Db": null,
|
||||
"TotalShards": 1
|
||||
"TotalShards": 1,
|
||||
"ShardRunCommand": ""
|
||||
}
|
||||
```
|
||||
-----
|
||||
@ -155,14 +156,28 @@ 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**
|
||||
- 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
|
||||
- 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:
|
||||
`NadekoBot/src/NadekoBot/bin/Release/netcoreapp1.1/data/NadekoBot.db` (macOS and Linux)
|
||||
`NadekoBot\system\data` (Windows)
|
||||
`NadekoBot\system\data` (Windows)
|
||||
|
||||
in order to open the database file you will need [DB Browser for SQLite](http://sqlitebrowser.org/).
|
||||
|
||||
*NOTE: You don't have to worry if you don't have `NadekoBot.db` file, it gets auto created once you run the bot successfully.*
|
||||
|
@ -13,6 +13,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
|
||||
/// Try to execute some logic within some module's service.
|
||||
/// </summary>
|
||||
/// <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);
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
@ -9,6 +9,6 @@ namespace NadekoBot.DataStructures.ModuleBehaviors
|
||||
/// </summary>
|
||||
public interface ILateExecutor
|
||||
{
|
||||
Task LateExecute(DiscordShardedClient client, IGuild guild, IUserMessage msg);
|
||||
Task LateExecute(DiscordSocketClient client, IGuild guild, IUserMessage msg);
|
||||
}
|
||||
}
|
||||
|
22
src/NadekoBot/DataStructures/Shard0Precondition.cs
Normal file
22
src/NadekoBot/DataStructures/Shard0Precondition.cs
Normal file
@ -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<PreconditionResult> 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"));
|
||||
}
|
||||
}
|
||||
}
|
16
src/NadekoBot/DataStructures/ShardCom/IShardComMessage.cs
Normal file
16
src/NadekoBot/DataStructures/ShardCom/IShardComMessage.cs
Normal 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; }
|
||||
}
|
||||
}
|
29
src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs
Normal file
29
src/NadekoBot/DataStructures/ShardCom/ShardComClient.cs
Normal file
@ -0,0 +1,29 @@
|
||||
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
|
||||
{
|
||||
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(), port).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs
Normal file
40
src/NadekoBot/DataStructures/ShardCom/ShardComServer.cs
Normal file
@ -0,0 +1,40 @@
|
||||
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
|
||||
{
|
||||
private readonly UdpClient _client;
|
||||
|
||||
public ShardComServer(int port)
|
||||
{
|
||||
_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; };
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -13,6 +13,8 @@ using NadekoBot.Services;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.Services.Administration;
|
||||
using System.Diagnostics;
|
||||
using NadekoBot.DataStructures;
|
||||
|
||||
namespace NadekoBot.Modules.Administration
|
||||
{
|
||||
@ -25,10 +27,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 +206,28 @@ namespace NadekoBot.Modules.Administration
|
||||
|
||||
}
|
||||
|
||||
[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);
|
||||
}
|
||||
}
|
||||
//todo 2 shard commands
|
||||
//[NadekoCommand, Usage, Description, Aliases]
|
||||
//[Shard0Precondition]
|
||||
//[OwnerOnly]
|
||||
//public async Task RestartShard(int shardid)
|
||||
//{
|
||||
// if (shardid == 0 || shardid > b)
|
||||
// {
|
||||
// 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)
|
||||
|
@ -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"))
|
||||
|
@ -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;
|
||||
|
@ -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<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;
|
||||
_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;
|
||||
|
@ -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<ulong> _flowerReactionAwardedUsers = new ConcurrentHashSet<ulong>();
|
||||
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;
|
||||
|
@ -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;
|
||||
|
@ -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<ulong, AcrophobiaGame> AcrophobiaGames { get; } = new ConcurrentDictionary<ulong, AcrophobiaGame>();
|
||||
|
||||
public Acropobia(DiscordShardedClient client)
|
||||
public Acropobia(DiscordSocketClient client)
|
||||
{
|
||||
_client = client;
|
||||
}
|
||||
@ -86,10 +86,10 @@ namespace NadekoBot.Modules.Games
|
||||
//text, votes
|
||||
private readonly ConcurrentDictionary<string, int> _votes = new ConcurrentDictionary<string, int>();
|
||||
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;
|
||||
|
@ -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<char> Guesses { get; } = new HashSet<char>();
|
||||
@ -82,7 +82,7 @@ namespace NadekoBot.Modules.Games.Hangman
|
||||
|
||||
public event Action<HangmanGame> OnEnded;
|
||||
|
||||
public HangmanGame(DiscordShardedClient client, IMessageChannel channel, string type)
|
||||
public HangmanGame(DiscordSocketClient client, IMessageChannel channel, string type)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -20,13 +20,13 @@ namespace NadekoBot.Modules.Games.Models
|
||||
public bool IsActive { get; private set; }
|
||||
private readonly Stopwatch sw;
|
||||
private readonly List<ulong> 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;
|
||||
|
@ -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))
|
||||
|
@ -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;
|
||||
@ -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)]
|
||||
@ -45,9 +39,9 @@ namespace NadekoBot.Modules.Games
|
||||
await Context.Channel.EmbedAsync(poll.GetStats(GetText("current_poll_results")));
|
||||
}
|
||||
|
||||
private async Task InternalStartPoll(string arg, bool isPublic = false)
|
||||
private async Task InternalStartPoll(string arg)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,9 @@ namespace NadekoBot.Modules.Games
|
||||
{
|
||||
public static ConcurrentDictionary<ulong, TypingGame> RunningContests = new ConcurrentDictionary<ulong, TypingGame>();
|
||||
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;
|
||||
|
@ -21,9 +21,9 @@ namespace NadekoBot.Modules.Games
|
||||
private static readonly Dictionary<ulong, TicTacToe> _games = new Dictionary<ulong, TicTacToe>();
|
||||
|
||||
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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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<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;
|
||||
_client = client;
|
||||
|
@ -155,8 +155,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]
|
||||
|
@ -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;
|
||||
|
@ -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<string> GetUserInputAsync(ulong userId, ulong channelId)
|
||||
{
|
||||
var userInputTask = new TaskCompletionSource<string>();
|
||||
var dsc = (DiscordShardedClient)Context.Client;
|
||||
var dsc = (DiscordSocketClient)Context.Client;
|
||||
try
|
||||
{
|
||||
dsc.MessageReceived += MessageReceived;
|
||||
|
@ -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()
|
||||
|
@ -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;
|
||||
|
@ -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<ITextChannel>();
|
||||
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<ITextChannel> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -6,7 +6,6 @@ using NadekoBot.Services.Utility;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
public partial class Utility
|
||||
|
@ -18,99 +18,25 @@ using Discord.WebSocket;
|
||||
using System.Diagnostics;
|
||||
using Color = Discord.Color;
|
||||
using NadekoBot.Services;
|
||||
using NadekoBot.DataStructures;
|
||||
|
||||
namespace NadekoBot.Modules.Utility
|
||||
{
|
||||
public partial class Utility : NadekoTopLevelModule
|
||||
{
|
||||
private static ConcurrentDictionary<ulong, Timer> _rotatingRoleColors = new ConcurrentDictionary<ulong, Timer>();
|
||||
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;
|
||||
}
|
||||
|
||||
//[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<string>(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<string>(reactions, r.Emoji.Name);
|
||||
// if (index == -1)
|
||||
// return;
|
||||
|
||||
// await usr.RemoveRolesAsync(roles[index]);
|
||||
// }
|
||||
// catch (Exception ex)
|
||||
// {
|
||||
// _log.Warn(ex);
|
||||
// }
|
||||
// }));
|
||||
//}
|
||||
|
||||
_bot = bot;
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[RequireContext(ContextType.Guild)]
|
||||
@ -354,23 +280,25 @@ namespace NadekoBot.Modules.Utility
|
||||
}
|
||||
|
||||
[NadekoCommand, Usage, Description, Aliases]
|
||||
[Shard0Precondition]
|
||||
public async Task ShardStats(int page = 1)
|
||||
{
|
||||
if (--page < 0)
|
||||
return;
|
||||
var statuses = _bot.ShardCoord.Statuses.ToArray()
|
||||
.Where(x => x != null);
|
||||
|
||||
var status = string.Join(", ", _client.Shards.GroupBy(x => x.ConnectionState)
|
||||
var status = string.Join(", ", statuses
|
||||
.GroupBy(x => x.ConnectionState)
|
||||
.Select(x => $"{x.Count()} {x.Key}")
|
||||
.ToArray());
|
||||
|
||||
var allShardStrings = _client.Shards
|
||||
var allShardStrings = statuses
|
||||
.Select(x =>
|
||||
GetText("shard_stats_txt", x.ShardId.ToString(),
|
||||
Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.Count.ToString())))
|
||||
Format.Bold(x.ConnectionState.ToString()), Format.Bold(x.Guilds.ToString())))
|
||||
.ToArray();
|
||||
|
||||
|
||||
|
||||
await Context.Channel.SendPaginatedConfirmAsync(_client, page, (curPage) =>
|
||||
{
|
||||
|
||||
@ -387,21 +315,9 @@ namespace NadekoBot.Modules.Utility
|
||||
}, 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);
|
||||
}
|
||||
|
||||
[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}")
|
||||
@ -409,7 +325,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))
|
||||
@ -417,13 +333,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]
|
||||
|
@ -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;
|
||||
@ -27,8 +25,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 +42,63 @@ namespace NadekoBot
|
||||
public static Color OkColor { 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 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; }
|
||||
public ShardsCoordinator ShardCoord { get; private set; }
|
||||
|
||||
private readonly ShardComClient _comClient;
|
||||
|
||||
public NadekoBot(int shardId, int parentProcessId, int? port = null)
|
||||
{
|
||||
SetupLogger();
|
||||
if (shardId < 0)
|
||||
throw new ArgumentOutOfRangeException(nameof(shardId));
|
||||
|
||||
ShardId = shardId;
|
||||
|
||||
LogSetup.SetupLogger();
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
TerribleElevatedPermissionCheck();
|
||||
|
||||
|
||||
Credentials = new BotCredentials();
|
||||
|
||||
port = port ?? Credentials.ShardRunPort;
|
||||
_comClient = new ShardComClient(port.Value);
|
||||
|
||||
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,
|
||||
});
|
||||
|
||||
@ -94,182 +107,245 @@ namespace NadekoBot
|
||||
CaseSensitiveCommands = false,
|
||||
DefaultRunMode = RunMode.Sync,
|
||||
});
|
||||
|
||||
//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);
|
||||
|
||||
SetupShard(shardId, parentProcessId, port.Value);
|
||||
|
||||
#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()
|
||||
{
|
||||
var soundcloudApiService = new SoundCloudApiService(Credentials);
|
||||
var startingGuildIdList = Client.Guilds.Select(x => (long)x.Id).ToList();
|
||||
|
||||
#region help
|
||||
var helpService = new HelpService(BotConfig, CommandHandler, Strings);
|
||||
#endregion
|
||||
//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);
|
||||
|
||||
//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 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
|
||||
var soundcloudApiService = new SoundCloudApiService(Credentials);
|
||||
|
||||
#region permissions
|
||||
var permissionsService = new PermissionService(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 help
|
||||
var helpService = new HelpService(BotConfig, CommandHandler, Strings);
|
||||
#endregion
|
||||
|
||||
#region Searches
|
||||
var searchesService = new SearchesService(Client, GoogleApi, Db);
|
||||
var streamNotificationService = new StreamNotificationService(Db, Client, Strings);
|
||||
var animeSearchService = new AnimeSearchService();
|
||||
#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, Client);
|
||||
var verboseErrorsService = new VerboseErrorsService(AllGuildConfigs, Db, CommandHandler, helpService);
|
||||
var pruneService = new PruneService();
|
||||
#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 permissions
|
||||
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);
|
||||
var globalPermsService = new GlobalPermissionService(BotConfig);
|
||||
#endregion
|
||||
|
||||
#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 Searches
|
||||
var searchesService = new SearchesService(Client, GoogleApi, Db);
|
||||
var streamNotificationService = new StreamNotificationService(Db, Client, Strings);
|
||||
var animeSearchService = new AnimeSearchService();
|
||||
#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
|
||||
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, Strings, Client, CommandHandler, BotConfig, uow);
|
||||
|
||||
#region pokemon
|
||||
var pokemonService = new PokemonService();
|
||||
#endregion
|
||||
#region Games
|
||||
var gamesService = new GamesService(Client, BotConfig, AllGuildConfigs, Strings, Images, CommandHandler);
|
||||
var chatterBotService = new ChatterBotService(Client, permissionsService, AllGuildConfigs, CommandHandler, Strings);
|
||||
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<ILocalization>(Localization)
|
||||
.Add<IStatsService>(Stats)
|
||||
.Add<IImagesService>(Images)
|
||||
.Add<IGoogleApiService>(GoogleApi)
|
||||
.Add<IStatsService>(Stats)
|
||||
.Add<IBotCredentials>(Credentials)
|
||||
.Add<CommandService>(CommandService)
|
||||
.Add<NadekoStrings>(Strings)
|
||||
.Add<DiscordShardedClient>(Client)
|
||||
.Add<BotConfig>(BotConfig)
|
||||
.Add<CurrencyService>(Currency)
|
||||
.Add<CommandHandler>(CommandHandler)
|
||||
.Add<DbService>(Db)
|
||||
//modules
|
||||
.Add(crossServerTextService)
|
||||
.Add(commandMapService)
|
||||
.Add(remindService)
|
||||
.Add(repeaterService)
|
||||
.Add(converterService)
|
||||
.Add(verboseErrorsService)
|
||||
.Add(patreonRewardsService)
|
||||
.Add(pruneService)
|
||||
.Add<SearchesService>(searchesService)
|
||||
.Add(streamNotificationService)
|
||||
.Add(animeSearchService)
|
||||
.Add<ClashOfClansService>(clashService)
|
||||
.Add<MusicService>(musicService)
|
||||
.Add<GreetSettingsService>(greetSettingsService)
|
||||
.Add<CustomReactionsService>(crService)
|
||||
.Add<HelpService>(helpService)
|
||||
.Add<GamesService>(gamesService)
|
||||
.Add(chatterBotService)
|
||||
.Add(pollService)
|
||||
.Add<AdministrationService>(administrationService)
|
||||
.Add(selfService)
|
||||
.Add(vcRoleService)
|
||||
.Add(vPlusTService)
|
||||
.Add(muteService)
|
||||
.Add(ratelimitService)
|
||||
.Add(playingRotateService)
|
||||
.Add(gameVcService)
|
||||
.Add(autoAssignRoleService)
|
||||
.Add(protectionService)
|
||||
.Add(logCommandService)
|
||||
.Add(guildTimezoneService)
|
||||
.Add<PermissionService>(permissionsService)
|
||||
.Add(blacklistService)
|
||||
.Add(cmdcdsService)
|
||||
.Add(filterService)
|
||||
.Add(globalPermsService)
|
||||
.Add<PokemonService>(pokemonService)
|
||||
.Build();
|
||||
|
||||
CommandHandler.AddServices(Services);
|
||||
//initialize Services
|
||||
Services = new NServiceProvider.ServiceProviderBuilder()
|
||||
.Add<ILocalization>(Localization)
|
||||
.Add<IStatsService>(Stats)
|
||||
.Add<IImagesService>(Images)
|
||||
.Add<IGoogleApiService>(GoogleApi)
|
||||
.Add<IStatsService>(Stats)
|
||||
.Add<IBotCredentials>(Credentials)
|
||||
.Add<CommandService>(CommandService)
|
||||
.Add<NadekoStrings>(Strings)
|
||||
.Add<DiscordSocketClient>(Client)
|
||||
.Add<BotConfig>(BotConfig)
|
||||
.Add<CurrencyService>(Currency)
|
||||
.Add<CommandHandler>(CommandHandler)
|
||||
.Add<DbService>(Db)
|
||||
//modules
|
||||
.Add(commandMapService)
|
||||
.Add(remindService)
|
||||
.Add(repeaterService)
|
||||
//.Add(converterService)
|
||||
.Add(verboseErrorsService)
|
||||
.Add(patreonRewardsService)
|
||||
.Add(pruneService)
|
||||
.Add<SearchesService>(searchesService)
|
||||
.Add(streamNotificationService)
|
||||
.Add(animeSearchService)
|
||||
.Add<ClashOfClansService>(clashService)
|
||||
.Add<MusicService>(musicService)
|
||||
.Add<GreetSettingsService>(greetSettingsService)
|
||||
.Add<CustomReactionsService>(crService)
|
||||
.Add<HelpService>(helpService)
|
||||
.Add<GamesService>(gamesService)
|
||||
.Add(chatterBotService)
|
||||
.Add(pollService)
|
||||
.Add<AdministrationService>(administrationService)
|
||||
.Add(selfService)
|
||||
.Add(vcRoleService)
|
||||
.Add(vPlusTService)
|
||||
.Add(muteService)
|
||||
.Add(ratelimitService)
|
||||
.Add(playingRotateService)
|
||||
.Add(gameVcService)
|
||||
.Add(autoAssignRoleService)
|
||||
.Add(protectionService)
|
||||
.Add(logCommandService)
|
||||
.Add(guildTimezoneService)
|
||||
.Add<PermissionService>(permissionsService)
|
||||
.Add(blacklistService)
|
||||
.Add(cmdcdsService)
|
||||
.Add(filterService)
|
||||
.Add(globalPermsService)
|
||||
.Add<PokemonService>(pokemonService)
|
||||
.Add<NadekoBot>(this)
|
||||
.Build();
|
||||
|
||||
//setup typereaders
|
||||
CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
|
||||
CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader(CommandService, CommandHandler));
|
||||
CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader(crService, CommandService, CommandHandler));
|
||||
CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader(CommandService));
|
||||
CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(CommandService));
|
||||
CommandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));
|
||||
CommandService.AddTypeReader<GuildDateTime>(new GuildDateTimeTypeReader(guildTimezoneService));
|
||||
|
||||
CommandHandler.AddServices(Services);
|
||||
|
||||
//setup typereaders
|
||||
CommandService.AddTypeReader<PermissionAction>(new PermissionActionTypeReader());
|
||||
CommandService.AddTypeReader<CommandInfo>(new CommandTypeReader(CommandService, CommandHandler));
|
||||
CommandService.AddTypeReader<CommandOrCrInfo>(new CommandOrCrTypeReader(crService, CommandService, CommandHandler));
|
||||
CommandService.AddTypeReader<ModuleInfo>(new ModuleTypeReader(CommandService));
|
||||
CommandService.AddTypeReader<ModuleOrCrInfo>(new ModuleOrCrTypeReader(CommandService));
|
||||
CommandService.AddTypeReader<IGuild>(new GuildTypeReader(Client));
|
||||
CommandService.AddTypeReader<GuildDateTime>(new GuildDateTimeTypeReader(guildTimezoneService));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoginAsync(string token)
|
||||
{
|
||||
_log.Info("Logging in...");
|
||||
//connect
|
||||
await Client.LoginAsync(TokenType.Bot, token).ConfigureAwait(false);
|
||||
await Client.StartAsync().ConfigureAwait(false);
|
||||
var clientReady = new TaskCompletionSource<bool>();
|
||||
|
||||
_log.Info("Waiting for all shards to connect...");
|
||||
while (!Client.Shards.All(x => x.ConnectionState == ConnectionState.Connected))
|
||||
Task SetClientReady()
|
||||
{
|
||||
_log.Info("Connecting... {0}/{1}", Client.Shards.Count(x => x.ConnectionState == ConnectionState.Connected), Client.Shards.Count);
|
||||
await Task.Delay(1000).ConfigureAwait(false);
|
||||
var _ = Task.Run(async () =>
|
||||
{
|
||||
clientReady.TrySetResult(true);
|
||||
try
|
||||
{
|
||||
foreach (var chan in (await Client.GetDMChannelsAsync()))
|
||||
{
|
||||
await chan.CloseAsync().ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
//connect
|
||||
try { sem.WaitOne(); } catch (AbandonedMutexException) { }
|
||||
|
||||
_log.Info("Shard {0} logging in ...", ShardId);
|
||||
|
||||
try
|
||||
{
|
||||
await Client.LoginAsync(TokenType.Bot, token).ConfigureAwait(false);
|
||||
await Client.StartAsync().ConfigureAwait(false);
|
||||
Client.Ready += SetClientReady;
|
||||
await clientReady.Task.ConfigureAwait(false);
|
||||
Client.Ready -= SetClientReady;
|
||||
}
|
||||
finally
|
||||
{
|
||||
_log.Info("Shard {0} logged in.", ShardId);
|
||||
sem.Release();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RunAsync(params string[] args)
|
||||
{
|
||||
if(ShardId == 0)
|
||||
_log.Info("Starting NadekoBot v" + StatsService.BotVersion);
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
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<IStatsService>();
|
||||
stats.Initialize();
|
||||
@ -290,15 +366,17 @@ 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(await stats.Print().ConfigureAwait(false));
|
||||
_log.Info($"Shard {ShardId} ready.");
|
||||
//_log.Info(await stats.Print().ConfigureAwait(false));
|
||||
}
|
||||
|
||||
private Task Client_Log(LogMessage arg)
|
||||
@ -313,7 +391,13 @@ namespace NadekoBot
|
||||
public async Task RunAndBlockAsync(params string[] args)
|
||||
{
|
||||
await RunAsync(args).ConfigureAwait(false);
|
||||
await Task.Delay(-1).ConfigureAwait(false);
|
||||
StartSendingData();
|
||||
if (ShardCoord != null)
|
||||
await ShardCoord.RunAndBlockAsync();
|
||||
else
|
||||
{
|
||||
await Task.Delay(-1).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void TerribleElevatedPermissionCheck()
|
||||
@ -331,18 +415,29 @@ namespace NadekoBot
|
||||
}
|
||||
}
|
||||
|
||||
private static void SetupLogger()
|
||||
private void SetupShard(int shardId, int parentProcessId, int port)
|
||||
{
|
||||
var logConfig = new LoggingConfiguration();
|
||||
var consoleTarget = new ColoredConsoleTarget()
|
||||
if (shardId != 0)
|
||||
{
|
||||
Layout = @"${date:format=HH\:mm\:ss} ${logger} | ${message}"
|
||||
};
|
||||
logConfig.AddTarget("Console", consoleTarget);
|
||||
|
||||
logConfig.LoggingRules.Add(new LoggingRule("*", LogLevel.Debug, consoleTarget));
|
||||
|
||||
LogManager.Configuration = logConfig;
|
||||
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(port);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -90,5 +90,6 @@
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Modules\Music\Classes\" />
|
||||
<Folder Include="Utility\Services\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
@ -2,7 +2,17 @@
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args) =>
|
||||
new NadekoBot().RunAndBlockAsync(args).GetAwaiter().GetResult();
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
7
src/NadekoBot/Properties/launchSettings.json
Normal file
7
src/NadekoBot/Properties/launchSettings.json
Normal file
@ -0,0 +1,7 @@
|
||||
{
|
||||
"profiles": {
|
||||
"NadekoBot": {
|
||||
"commandName": "Project"
|
||||
}
|
||||
}
|
||||
}
|
@ -3096,14 +3096,14 @@
|
||||
<data name="shardstats_usage" xml:space="preserve">
|
||||
<value>`{0}shardstats` or `{0}shardstats 2`</value>
|
||||
</data>
|
||||
<data name="connectshard_cmd" xml:space="preserve">
|
||||
<value>connectshard</value>
|
||||
<data name="restartshard_cmd" xml:space="preserve">
|
||||
<value>restartshard</value>
|
||||
</data>
|
||||
<data name="connectshard_desc" xml:space="preserve">
|
||||
<data name="restartshard_desc" xml:space="preserve">
|
||||
<value>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.</value>
|
||||
</data>
|
||||
<data name="connectshard_usage" xml:space="preserve">
|
||||
<value>`{0}connectshard 2`</value>
|
||||
<data name="restartshard_usage" xml:space="preserve">
|
||||
<value>`{0}restartshard 2`</value>
|
||||
</data>
|
||||
<data name="shardid_cmd" xml:space="preserve">
|
||||
<value>shardid</value>
|
||||
|
@ -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<ulong, ulong> AutoAssignedRoles { get; }
|
||||
|
||||
public AutoAssignRoleService(DiscordShardedClient client, IEnumerable<GuildConfig> gcs)
|
||||
public AutoAssignRoleService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
|
@ -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<GuildConfig> gcs)
|
||||
public GameVoiceChannelService(DiscordSocketClient client, DbService db, IEnumerable<GuildConfig> gcs)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_db = db;
|
||||
|
@ -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<GuildConfig> 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<SocketGuild> 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<SocketGuild> 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<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
});
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
// PresenceUpdates.AddOrUpdate(logChannel, new List<string>() { str }, (id, list) => { list.Add(str); return list; });
|
||||
// }
|
||||
// catch
|
||||
// {
|
||||
// // ignored
|
||||
// }
|
||||
// });
|
||||
// return Task.CompletedTask;
|
||||
//}
|
||||
|
||||
private Task _client_UserLeft(IGuildUser usr)
|
||||
{
|
||||
|
@ -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<GuildConfig> gcs, DbService db)
|
||||
public MuteService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, DbService db)
|
||||
{
|
||||
_client = client;
|
||||
_db = db;
|
||||
|
@ -17,7 +17,7 @@ namespace NadekoBot.Services.Administration
|
||||
public List<PlayingStatus> 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<string, Func<DiscordShardedClient, MusicService, string>> PlayingPlaceholders { get; } =
|
||||
new Dictionary<string, Func<DiscordShardedClient, MusicService, string>> {
|
||||
public Dictionary<string, Func<DiscordSocketClient, MusicService, string>> PlayingPlaceholders { get; } =
|
||||
new Dictionary<string, Func<DiscordSocketClient, MusicService, string>> {
|
||||
{ "%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<string, Func<DiscordSocketClient, string>> ShardSpecificPlaceholders { get; } =
|
||||
|
@ -21,10 +21,10 @@ namespace NadekoBot.Services.Administration
|
||||
public event Func<PunishmentAction, ProtectionType, IGuildUser[], Task> 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<GuildConfig> gcs, MuteService mute)
|
||||
public ProtectionService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, MuteService mute)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_client = client;
|
||||
|
@ -19,9 +19,9 @@ namespace NadekoBot.Services.Administration
|
||||
public ConcurrentDictionary<ulong, HashSet<ulong>> IgnoredUsers = new ConcurrentDictionary<ulong, HashSet<ulong>>();
|
||||
|
||||
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();
|
||||
_client = client;
|
||||
|
@ -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<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)
|
||||
{
|
||||
_bot = bot;
|
||||
@ -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 () =>
|
||||
{
|
||||
@ -67,12 +63,8 @@ namespace NadekoBot.Services.Administration
|
||||
|
||||
_client.Guilds.SelectMany(g => g.Users);
|
||||
|
||||
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.");
|
||||
if(client.ShardId == 0)
|
||||
LoadOwnerChannels();
|
||||
});
|
||||
}
|
||||
|
||||
@ -81,11 +73,9 @@ namespace NadekoBot.Services.Administration
|
||||
var hs = new HashSet<ulong>(_creds.OwnerIds);
|
||||
var channels = new Dictionary<ulong, AsyncLazy<IDMChannel>>();
|
||||
|
||||
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;
|
||||
@ -105,10 +95,15 @@ 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)
|
||||
{
|
||||
|
@ -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<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();
|
||||
_db = db;
|
||||
|
@ -20,12 +20,12 @@ namespace NadekoBot.Services.Administration
|
||||
public readonly ConcurrentHashSet<ulong> VoicePlusTextCache;
|
||||
|
||||
private readonly ConcurrentDictionary<ulong, SemaphoreSlim> _guildLockObjects = new ConcurrentDictionary<ulong, SemaphoreSlim>();
|
||||
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<GuildConfig> gcs, NadekoStrings strings,
|
||||
public VplusTService(DiscordSocketClient client, IEnumerable<GuildConfig> gcs, NadekoStrings strings,
|
||||
DbService db)
|
||||
{
|
||||
_client = client;
|
||||
|
@ -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;
|
||||
@ -17,7 +18,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,28 +26,27 @@ namespace NadekoBot.Services.ClashOfClans
|
||||
|
||||
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, IUnitOfWork uow,
|
||||
List<long> guilds)
|
||||
{
|
||||
_client = client;
|
||||
_db = db;
|
||||
_localization = localization;
|
||||
_strings = strings;
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
ClashWars = new ConcurrentDictionary<ulong, List<ClashWar>>(
|
||||
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<ulong, List<ClashWar>>(
|
||||
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 _ =>
|
||||
{
|
||||
|
@ -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<ulong> UsersOnShortCooldown { get; } = new ConcurrentHashSet<ulong>();
|
||||
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;
|
||||
_commandService = commandService;
|
||||
|
@ -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
|
||||
{
|
||||
@ -22,13 +23,14 @@ 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;
|
||||
private readonly NadekoStrings _strings;
|
||||
|
||||
public CustomReactionsService(PermissionService perms, DbService db,
|
||||
DiscordShardedClient client, CommandHandler cmd, BotConfig bc)
|
||||
public CustomReactionsService(PermissionService perms, DbService db, NadekoStrings strings,
|
||||
DiscordSocketClient client, CommandHandler cmd, BotConfig bc, IUnitOfWork uow)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_db = db;
|
||||
@ -36,16 +38,11 @@ namespace NadekoBot.Services.CustomReactions
|
||||
_perms = perms;
|
||||
_cmd = cmd;
|
||||
_bc = bc;
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
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()));
|
||||
GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
|
||||
}
|
||||
sw.Stop();
|
||||
_log.Debug($"Loaded in {sw.Elapsed.TotalSeconds:F2}s");
|
||||
_strings = strings;
|
||||
|
||||
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()));
|
||||
GlobalReactions = items.Where(g => g.GuildId == null || g.GuildId == 0).ToArray();
|
||||
}
|
||||
|
||||
public void ClearStats() => ReactionStats.Clear();
|
||||
@ -98,7 +95,7 @@ namespace NadekoBot.Services.CustomReactions
|
||||
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
|
||||
var cr = await Task.Run(() => TryGetCustomReaction(msg)).ConfigureAwait(false);
|
||||
@ -114,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);
|
||||
}
|
||||
|
@ -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}>"; } },
|
||||
{"%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<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)
|
||||
{
|
||||
@ -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<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));
|
||||
|
||||
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;
|
||||
|
||||
|
@ -19,7 +19,9 @@ namespace NadekoBot.Services.Database
|
||||
{
|
||||
var optionsBuilder = new DbContextOptionsBuilder();
|
||||
optionsBuilder.UseSqlite("Filename=./data/NadekoBot.db");
|
||||
return new NadekoContext(optionsBuilder.Options);
|
||||
var ctx = new NadekoContext(optionsBuilder.Options);
|
||||
ctx.Database.SetCommandTimeout(60);
|
||||
return ctx;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,6 @@ namespace NadekoBot.Services.Database.Repositories
|
||||
{
|
||||
public interface IClashOfClansRepository : IRepository<ClashWar>
|
||||
{
|
||||
IEnumerable<ClashWar> GetAllWars();
|
||||
IEnumerable<ClashWar> GetAllWars(List<long> guilds);
|
||||
}
|
||||
}
|
||||
|
@ -11,10 +11,10 @@ namespace NadekoBot.Services.Database.Repositories
|
||||
GuildConfig For(ulong guildId, Func<DbSet<GuildConfig>, IQueryable<GuildConfig>> includes = null);
|
||||
GuildConfig LogSettingsFor(ulong guildId);
|
||||
IEnumerable<GuildConfig> OldPermissionsForAll();
|
||||
IEnumerable<GuildConfig> GetAllGuildConfigs();
|
||||
IEnumerable<FollowedStream> GetAllFollowedStreams();
|
||||
IEnumerable<GuildConfig> GetAllGuildConfigs(List<long> availableGuilds);
|
||||
IEnumerable<FollowedStream> GetAllFollowedStreams(List<long> included);
|
||||
void SetCleverbotEnabled(ulong id, bool cleverbotEnabled);
|
||||
IEnumerable<GuildConfig> Permissionsv2ForAll();
|
||||
IEnumerable<GuildConfig> Permissionsv2ForAll(List<long> include);
|
||||
GuildConfig GcWithPermissionsv2For(ulong guildId);
|
||||
}
|
||||
}
|
||||
|
@ -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<Reminder>
|
||||
{
|
||||
|
||||
IEnumerable<Reminder> GetIncludedReminders(List<long> guildIds);
|
||||
}
|
||||
}
|
||||
|
@ -11,9 +11,11 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
{
|
||||
}
|
||||
|
||||
public IEnumerable<ClashWar> GetAllWars()
|
||||
public IEnumerable<ClashWar> GetAllWars(List<long> 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;
|
||||
|
@ -24,8 +24,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
}
|
||||
};
|
||||
|
||||
public IEnumerable<GuildConfig> GetAllGuildConfigs() =>
|
||||
_set.Include(gc => gc.LogSetting)
|
||||
public IEnumerable<GuildConfig> GetAllGuildConfigs(List<long> 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)
|
||||
@ -42,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();
|
||||
|
||||
/// <summary>
|
||||
@ -134,9 +137,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
return query.ToList();
|
||||
}
|
||||
|
||||
public IEnumerable<GuildConfig> Permissionsv2ForAll()
|
||||
public IEnumerable<GuildConfig> Permissionsv2ForAll(List<long> include)
|
||||
{
|
||||
var query = _set
|
||||
.Where(x => include.Contains((long)x.GuildId))
|
||||
.Include(gc => gc.Permissions);
|
||||
|
||||
return query.ToList();
|
||||
@ -167,8 +171,10 @@ namespace NadekoBot.Services.Database.Repositories.Impl
|
||||
return config;
|
||||
}
|
||||
|
||||
public IEnumerable<FollowedStream> GetAllFollowedStreams() =>
|
||||
_set.Include(gc => gc.FollowedStreams)
|
||||
public IEnumerable<FollowedStream> GetAllFollowedStreams(List<long> included) =>
|
||||
_set
|
||||
.Where(gc => included.Contains((long)gc.GuildId))
|
||||
.Include(gc => gc.FollowedStreams)
|
||||
.SelectMany(gc => gc.FollowedStreams)
|
||||
.ToList();
|
||||
|
||||
|
@ -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<Reminder> GetIncludedReminders(List<long> guildIds)
|
||||
{
|
||||
return _set.Where(x => guildIds.Contains((long)x.ServerId)).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -32,9 +32,21 @@ namespace NadekoBot.Services
|
||||
public NadekoContext GetDbContext()
|
||||
{
|
||||
var context = new NadekoContext(options);
|
||||
context.Database.SetCommandTimeout(60);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,7 @@ namespace NadekoBot.Services.Discord
|
||||
public event Action<SocketReaction> 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()
|
||||
{
|
||||
|
@ -15,19 +15,22 @@ 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;
|
||||
private readonly NadekoStrings _strings;
|
||||
|
||||
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, NadekoStrings strings)
|
||||
{
|
||||
_client = client;
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
_perms = perms;
|
||||
_cmd = cmd;
|
||||
_strings = strings;
|
||||
|
||||
ChatterBotGuilds = new ConcurrentDictionary<ulong, Lazy<ChatterBotSession>>(
|
||||
gcs.Where(gc => gc.CleverbotEnabled)
|
||||
@ -83,7 +86,7 @@ namespace NadekoBot.Services.Games
|
||||
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))
|
||||
return false;
|
||||
@ -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);
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace NadekoBot.Services.Games
|
||||
public readonly ImmutableArray<string> 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<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)
|
||||
{
|
||||
_bc = bc;
|
||||
|
@ -18,16 +18,13 @@ namespace NadekoBot.Services.Games
|
||||
private string[] answers { get; }
|
||||
private readonly ConcurrentDictionary<ulong, int> _participants = new ConcurrentDictionary<ulong, int>();
|
||||
private readonly string _question;
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly NadekoStrings _strings;
|
||||
private bool running = false;
|
||||
private HashSet<ulong> _guildUsers;
|
||||
|
||||
public event Action<ulong> OnEnded = delegate { };
|
||||
|
||||
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)
|
||||
{
|
||||
_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<ulong>((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;
|
||||
|
@ -13,17 +13,17 @@ namespace NadekoBot.Services.Games
|
||||
{
|
||||
public ConcurrentDictionary<ulong, Poll> ActivePolls = new ConcurrentDictionary<ulong, Poll>();
|
||||
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;
|
||||
_strings = strings;
|
||||
}
|
||||
|
||||
public async Task<bool?> StartPoll(ITextChannel channel, IUserMessage msg, string arg, bool isPublic = false)
|
||||
public async Task<bool?> 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) =>
|
||||
@ -45,20 +45,10 @@ namespace NadekoBot.Services.Games
|
||||
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)
|
||||
{
|
||||
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;
|
||||
|
@ -17,10 +17,10 @@ namespace NadekoBot.Services
|
||||
private readonly DbService _db;
|
||||
|
||||
public readonly ConcurrentDictionary<ulong, GreetSettings> GuildConfigsCache;
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly DiscordSocketClient _client;
|
||||
private readonly Logger _log;
|
||||
|
||||
public GreetSettingsService(DiscordShardedClient client, IEnumerable<GuildConfig> guildConfigs, DbService db)
|
||||
public GreetSettingsService(DiscordSocketClient client, IEnumerable<GuildConfig> guildConfigs, DbService db)
|
||||
{
|
||||
_db = db;
|
||||
_client = client;
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -19,6 +19,9 @@ namespace NadekoBot.Services
|
||||
string OsuApiKey { get; }
|
||||
|
||||
bool IsOwner(IUser u);
|
||||
int TotalShards { get; }
|
||||
string ShardRunCommand { get; }
|
||||
string ShardRunArguments { get; }
|
||||
}
|
||||
|
||||
public class DBConfig
|
||||
|
@ -18,6 +18,6 @@ namespace NadekoBot.Services
|
||||
ImmutableArray<byte> WifeMatrix { get; }
|
||||
ImmutableArray<byte> RategirlDot { get; }
|
||||
|
||||
TimeSpan Reload();
|
||||
void Reload();
|
||||
}
|
||||
}
|
||||
|
@ -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 = ", ");
|
||||
|
@ -30,20 +30,23 @@ 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 int ShardRunPort { 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 +64,24 @@ 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} {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);
|
||||
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)];
|
||||
@ -81,7 +95,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)
|
||||
@ -107,6 +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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -13,11 +13,11 @@ namespace NadekoBot.Services.Impl
|
||||
{
|
||||
public class StatsService : IStatsService
|
||||
{
|
||||
private readonly DiscordShardedClient _client;
|
||||
private readonly DiscordSocketClient _client;
|
||||
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";
|
||||
@ -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(DiscordShardedClient 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));
|
||||
@ -121,31 +126,34 @@ namespace NadekoBot.Services.Impl
|
||||
return Task.CompletedTask;
|
||||
};
|
||||
|
||||
_carbonitexTimer = new Timer(async (state) =>
|
||||
if (sc != null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(_creds.CarbonKey))
|
||||
return;
|
||||
try
|
||||
_carbonitexTimer = new Timer(async (state) =>
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
if (string.IsNullOrWhiteSpace(_creds.CarbonKey))
|
||||
return;
|
||||
try
|
||||
{
|
||||
using (var content = new FormUrlEncodedContent(
|
||||
new Dictionary<string, string> {
|
||||
{ "servercount", _client.Guilds.Count.ToString() },
|
||||
{ "key", _creds.CarbonKey }}))
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
content.Headers.Clear();
|
||||
content.Headers.Add("Content-Type", "application/x-www-form-urlencoded");
|
||||
using (var content = new FormUrlEncodedContent(
|
||||
new Dictionary<string, string> {
|
||||
{ "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);
|
||||
await http.PostAsync("https://www.carbonitex.net/discord/data/botdata.php", content).ConfigureAwait(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1));
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}, null, TimeSpan.FromHours(1), TimeSpan.FromHours(1));
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize()
|
||||
|
28
src/NadekoBot/Services/LogSetup.cs
Normal file
28
src/NadekoBot/Services/LogSetup.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@ -21,7 +21,7 @@ namespace NadekoBot.Services.Permissions
|
||||
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)
|
||||
{
|
||||
if (guild == null)
|
||||
|
@ -41,7 +41,7 @@ namespace NadekoBot.Services.Permissions
|
||||
return words;
|
||||
}
|
||||
|
||||
public FilterService(DiscordShardedClient _client, IEnumerable<GuildConfig> gcs)
|
||||
public FilterService(DiscordSocketClient _client, IEnumerable<GuildConfig> gcs)
|
||||
{
|
||||
_log = LogManager.GetCurrentClassLogger();
|
||||
|
||||
|
@ -19,7 +19,7 @@ namespace NadekoBot.Services.Permissions
|
||||
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();
|
||||
commandName = commandName.ToLowerInvariant();
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using NadekoBot.DataStructures.ModuleBehaviors;
|
||||
using NadekoBot.Services.Database.Models;
|
||||
using NLog;
|
||||
@ -10,6 +11,7 @@ using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using NadekoBot.Extensions;
|
||||
using NadekoBot.Services;
|
||||
|
||||
namespace NadekoBot.Services.Permissions
|
||||
{
|
||||
@ -18,22 +20,26 @@ 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<ulong, PermissionCache> Cache { get; } =
|
||||
new ConcurrentDictionary<ulong, PermissionCache>();
|
||||
|
||||
public PermissionService(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();
|
||||
TryMigratePermissions(bc);
|
||||
if (client.ShardId == 0)
|
||||
TryMigratePermissions(bc);
|
||||
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
foreach (var x in uow.GuildConfigs.Permissionsv2ForAll())
|
||||
foreach (var x in uow.GuildConfigs.Permissionsv2ForAll(client.Guilds.ToArray().Select(x => (long)x.Id).ToList()))
|
||||
{
|
||||
Cache.TryAdd(x.GuildId, new PermissionCache()
|
||||
{
|
||||
@ -68,10 +74,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<ulong, OldPermissionCache>(uow.GuildConfigs
|
||||
@ -126,9 +131,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(
|
||||
@ -144,9 +153,9 @@ WHERE secondaryTargetName LIKE '.%' OR
|
||||
secondaryTargetName LIKE '>%' OR
|
||||
secondaryTargetName LIKE '-%' OR
|
||||
secondaryTargetName LIKE '!%';");
|
||||
_bc.PermissionVersion = 3;
|
||||
bc.PermissionVersion = 3;
|
||||
uow.Complete();
|
||||
}
|
||||
uow.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,7 +192,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();
|
||||
if (guild == null)
|
||||
@ -198,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));
|
||||
}
|
||||
|
||||
|
||||
@ -215,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."));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,52 +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
|
||||
{
|
||||
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<string, string>
|
||||
{
|
||||
{"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<AnimeResult> GetAnimeData(string query)
|
||||
@ -56,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<AnimeResult>(aniData); } catch { return null; } }).ConfigureAwait(false);
|
||||
var res = await http.GetStringAsync(link).ConfigureAwait(false);
|
||||
return JsonConvert.DeserializeObject<AnimeResult>(res);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
_log.Warn(ex, "Failed anime search for {0}", query);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -79,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<MangaResult>(aniData); } catch { return null; } }).ConfigureAwait(false);
|
||||
var res = await http.GetStringAsync(link).ConfigureAwait(false);
|
||||
return JsonConvert.DeserializeObject<MangaResult>(res);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
catch
|
||||
{
|
||||
_log.Warn(ex, "Failed anime search for {0}", query);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -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<WoWJoke> WowJokes { get; } = new List<WoWJoke>();
|
||||
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;
|
||||
_google = google;
|
||||
|
@ -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;
|
||||
@ -20,10 +22,10 @@ namespace NadekoBot.Services.Searches
|
||||
private readonly ConcurrentDictionary<string, StreamStatus> _cachedStatuses = new ConcurrentDictionary<string, StreamStatus>();
|
||||
|
||||
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;
|
||||
@ -35,7 +37,7 @@ namespace NadekoBot.Services.Searches
|
||||
IEnumerable<FollowedStream> 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 =>
|
||||
@ -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<StreamStatus> GetStreamStatus(FollowedStream stream, bool checkCache = true)
|
||||
|
@ -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;
|
||||
@ -13,24 +15,26 @@ namespace NadekoBot.Services.Utility
|
||||
{
|
||||
public class ConverterService
|
||||
{
|
||||
public List<ConvertUnit> Units { get; set; } = new List<ConvertUnit>();
|
||||
public List<ConvertUnit> Units { get; } = new List<ConvertUnit>();
|
||||
private readonly Logger _log;
|
||||
private Timer _timer;
|
||||
private readonly Timer _currencyUpdater;
|
||||
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<List<MeasurementUnit>>(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<List<MeasurementUnit>>(
|
||||
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)
|
||||
{
|
||||
@ -47,10 +51,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<Rates> UpdateCurrencyRates()
|
||||
private async Task<Rates> GetCurrencyRates()
|
||||
{
|
||||
using (var http = new HttpClient())
|
||||
{
|
||||
@ -59,38 +63,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
|
||||
{
|
||||
|
@ -15,7 +15,7 @@ namespace NadekoBot.Services.Utility
|
||||
public ConcurrentDictionary<ulong, ConcurrentQueue<RepeatRunner>> Repeaters { get; 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 () =>
|
||||
{
|
||||
|
@ -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;
|
||||
|
||||
@ -23,12 +26,15 @@ 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)
|
||||
private readonly string cacheFileName = "./patreon-rewards.json";
|
||||
|
||||
public PatreonRewardsService(IBotCredentials creds, DbService db, CurrencyService currency,
|
||||
DiscordSocketClient client)
|
||||
{
|
||||
_creds = creds;
|
||||
_db = db;
|
||||
@ -36,58 +42,65 @@ 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, client.ShardId == 0 ? TimeSpan.Zero : TimeSpan.FromMinutes(2), 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<PatreonPledge>();
|
||||
var users = new List<PatreonUser>();
|
||||
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<PatreonPledge>();
|
||||
var users = new List<PatreonUser>();
|
||||
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<PatreonData>(res);
|
||||
var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge");
|
||||
rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject<PatreonPledge>(x.ToString()))
|
||||
.Where(x => x.attributes.declined_since == null));
|
||||
users.AddRange(data.Included
|
||||
.Where(x => x["type"].ToString() == "user")
|
||||
.Select(x => JsonConvert.DeserializeObject<PatreonUser>(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<PatreonData>(res);
|
||||
var pledgers = data.Data.Where(x => x["type"].ToString() == "pledge");
|
||||
rewards.AddRange(pledgers.Select(x => JsonConvert.DeserializeObject<PatreonPledge>(x.ToString()))
|
||||
.Where(x => x.attributes.declined_since == null));
|
||||
users.AddRange(data.Included
|
||||
.Where(x => x["type"].ToString() == "user")
|
||||
.Select(x => JsonConvert.DeserializeObject<PatreonUser>(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
|
||||
{
|
||||
if(File.Exists(cacheFileName))
|
||||
Pledges = JsonConvert.DeserializeObject<PatreonUserAndReward[]>(File.ReadAllText("./patreon_rewards.json"))
|
||||
.ToImmutableArray();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
@ -30,10 +31,11 @@ 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,
|
||||
List<long> guilds, IUnitOfWork uow)
|
||||
{
|
||||
_config = config;
|
||||
_client = client;
|
||||
@ -42,11 +44,8 @@ namespace NadekoBot.Services.Utility
|
||||
|
||||
cancelSource = new CancellationTokenSource();
|
||||
cancelAllToken = cancelSource.Token;
|
||||
List<Reminder> reminders;
|
||||
using (var uow = _db.UnitOfWork)
|
||||
{
|
||||
reminders = uow.Reminders.GetAll().ToList();
|
||||
}
|
||||
|
||||
var reminders = uow.Reminders.GetIncludedReminders(guilds).ToList();
|
||||
RemindMessageFormat = _config.RemindMessageFormat;
|
||||
|
||||
foreach (var r in reminders)
|
||||
|
@ -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;
|
||||
|
@ -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<int, ConcurrentHashSet<ITextChannel>> Subscribers =
|
||||
new ConcurrentDictionary<int, ConcurrentHashSet<ITextChannel>>();
|
||||
private DiscordShardedClient _client;
|
||||
|
||||
public CrossServerTextService(IEnumerable<GuildConfig> guildConfigs, DiscordShardedClient 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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
109
src/NadekoBot/ShardsCoordinator.cs
Normal file
109
src/NadekoBot/ShardsCoordinator.cs
Normal file
@ -0,0 +1,109 @@
|
||||
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;
|
||||
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;
|
||||
private readonly int _port;
|
||||
|
||||
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(port);
|
||||
_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.ToString());
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public async Task RunAsync()
|
||||
{
|
||||
var curProcessId = Process.GetCurrentProcess().Id;
|
||||
for (int i = 1; i < Credentials.TotalShards; i++)
|
||||
{
|
||||
var p = Process.Start(new ProcessStartInfo()
|
||||
{
|
||||
FileName = Credentials.ShardRunCommand,
|
||||
Arguments = string.Format(Credentials.ShardRunArguments, i, curProcessId, _port)
|
||||
});
|
||||
await Task.Delay(5000);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task RunAndBlockAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
await RunAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Error(ex);
|
||||
}
|
||||
await Task.Run(() =>
|
||||
{
|
||||
string input;
|
||||
while ((input = Console.ReadLine()?.ToLowerInvariant()) != "quit")
|
||||
{
|
||||
try
|
||||
{
|
||||
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
|
||||
.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;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_log.Warn(ex);
|
||||
}
|
||||
}
|
||||
});
|
||||
foreach (var p in ShardProcesses)
|
||||
{
|
||||
try { p.Kill(); } catch { }
|
||||
try { p.Dispose(); } catch { }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -70,7 +70,7 @@ namespace NadekoBot.Extensions
|
||||
/// <summary>
|
||||
/// danny kamisama
|
||||
/// </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);
|
||||
|
||||
@ -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<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)
|
||||
reactionRemoved = delegate { };
|
||||
|
@ -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.",
|
||||
@ -613,9 +614,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",
|
||||
|
@ -15,5 +15,9 @@
|
||||
"Type": "sqlite",
|
||||
"ConnectionString": "Filename=./data/NadekoBot.db"
|
||||
},
|
||||
"TotalShards": 1
|
||||
"TotalShards": 1,
|
||||
"PatreonAccessToken": "",
|
||||
"ShardRunCommand": "",
|
||||
"ShardRunArguments": "",
|
||||
"ShardRunPort": null
|
||||
}
|
Loading…
Reference in New Issue
Block a user