Attempt to improve code quality with a fearless refactor
- Completely refactor Program.cs - Split Handlers into separate files - Split up the command handler into multiple functions
This commit is contained in:
parent
f7908c2a0c
commit
83dc2c8e49
8 changed files with 488 additions and 381 deletions
|
@ -1,280 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Rest;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Geekbot.net.Lib.ReactionListener;
|
||||
using Geekbot.net.Lib.UserRepository;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Geekbot.net
|
||||
{
|
||||
public class Handlers
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IDiscordClient _client;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly IServiceProvider _servicesProvider;
|
||||
private readonly CommandService _commands;
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IReactionListener _reactionListener;
|
||||
private readonly DatabaseContext _messageCounterDatabaseContext;
|
||||
private readonly RestApplication _applicationInfo;
|
||||
private readonly List<ulong> _ignoredServers;
|
||||
|
||||
public Handlers(DatabaseInitializer databaseInitializer, IDiscordClient client, IGeekbotLogger logger,
|
||||
IServiceProvider servicesProvider, CommandService commands, IUserRepository userRepository,
|
||||
IReactionListener reactionListener, RestApplication applicationInfo)
|
||||
{
|
||||
_database = databaseInitializer.Initialize();
|
||||
_messageCounterDatabaseContext = databaseInitializer.Initialize();
|
||||
_client = client;
|
||||
_logger = logger;
|
||||
_servicesProvider = servicesProvider;
|
||||
_commands = commands;
|
||||
_userRepository = userRepository;
|
||||
_reactionListener = reactionListener;
|
||||
_applicationInfo = applicationInfo;
|
||||
// ToDo: create a clean solution for this...
|
||||
_ignoredServers = new List<ulong>()
|
||||
{
|
||||
228623803201224704, // SwitzerLAN
|
||||
169844523181015040, // EEvent
|
||||
248531441548263425, // MYI
|
||||
110373943822540800 // Discord Bots
|
||||
};
|
||||
}
|
||||
|
||||
//
|
||||
// Incoming Messages
|
||||
//
|
||||
|
||||
public Task RunCommand(SocketMessage messageParam)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(messageParam is SocketUserMessage message)) return Task.CompletedTask;
|
||||
if (message.Author.IsBot) return Task.CompletedTask;
|
||||
var argPos = 0;
|
||||
|
||||
var guildId = ((SocketGuildChannel) message.Channel).Guild.Id;
|
||||
// Some guilds only wanted very specific functionally without any of the commands, a quick hack that solves that short term...
|
||||
// ToDo: cleanup
|
||||
if (_ignoredServers.Contains(guildId))
|
||||
{
|
||||
if (message.Author.Id != _applicationInfo.Owner.Id)
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
var lowCaseMsg = message.ToString().ToLower();
|
||||
if (lowCaseMsg.StartsWith("hui"))
|
||||
{
|
||||
var hasPing = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId.Equals(guildId.AsLong()))?.Hui ?? false;
|
||||
if (hasPing)
|
||||
{
|
||||
message.Channel.SendMessageAsync("hui!!!");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
if (lowCaseMsg.StartsWith("ping ") || lowCaseMsg.Equals("ping"))
|
||||
{
|
||||
var hasPing = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId.Equals(guildId.AsLong()))?.Ping ?? false;
|
||||
if (hasPing)
|
||||
{
|
||||
message.Channel.SendMessageAsync("pong");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(message.HasCharPrefix('!', ref argPos) ||
|
||||
message.HasMentionPrefix(_client.CurrentUser, ref argPos))) return Task.CompletedTask;
|
||||
var context = new CommandContext(_client, message);
|
||||
_commands.ExecuteAsync(context, argPos, _servicesProvider);
|
||||
_logger.Information(LogSource.Command,
|
||||
context.Message.Content.Split(" ")[0].Replace("!", ""),
|
||||
SimpleConextConverter.ConvertContext(context));
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to Process Message", e);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UpdateStats(SocketMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (message == null) return;
|
||||
if (message.Channel.Name.StartsWith('@'))
|
||||
{
|
||||
_logger.Information(LogSource.Message, $"[DM-Channel] {message.Content}", SimpleConextConverter.ConvertSocketMessage(message, true));
|
||||
return;
|
||||
}
|
||||
|
||||
var channel = (SocketGuildChannel) message.Channel;
|
||||
|
||||
var rowId = await _messageCounterDatabaseContext.Database.ExecuteSqlRawAsync(
|
||||
"UPDATE \"Messages\" SET \"MessageCount\" = \"MessageCount\" + 1 WHERE \"GuildId\" = {0} AND \"UserId\" = {1}",
|
||||
channel.Guild.Id.AsLong(),
|
||||
message.Author.Id.AsLong()
|
||||
);
|
||||
|
||||
if (rowId == 0)
|
||||
{
|
||||
_messageCounterDatabaseContext.Messages.Add(new MessagesModel
|
||||
{
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
GuildId = channel.Guild.Id.AsLong(),
|
||||
MessageCount = 1
|
||||
});
|
||||
_messageCounterDatabaseContext.SaveChanges();
|
||||
}
|
||||
|
||||
if (message.Author.IsBot) return;
|
||||
_logger.Information(LogSource.Message, message.Content, SimpleConextConverter.ConvertSocketMessage(message));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Message, "Could not process message stats", e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// User Stuff
|
||||
//
|
||||
|
||||
public async Task UserJoined(SocketGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userRepoUpdate = _userRepository.Update(user);
|
||||
_logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||
|
||||
if (!user.IsBot)
|
||||
{
|
||||
var guildSettings = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId == user.Guild.Id.AsLong());
|
||||
var message = guildSettings?.WelcomeMessage;
|
||||
if (string.IsNullOrEmpty(message)) return;
|
||||
message = message.Replace("$user", user.Mention);
|
||||
|
||||
var fallbackSender = new Func<Task<RestUserMessage>>(() => user.Guild.DefaultChannel.SendMessageAsync(message));
|
||||
if (guildSettings.WelcomeChannel != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var target = await _client.GetChannelAsync(guildSettings.WelcomeChannel.AsUlong());
|
||||
var channel = target as ISocketMessageChannel;
|
||||
await channel.SendMessageAsync(message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send welcome message to user defined welcome channel", e);
|
||||
await fallbackSender();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await fallbackSender();
|
||||
}
|
||||
}
|
||||
|
||||
await userRepoUpdate;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send welcome message", e);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task UserUpdated(SocketUser oldUser, SocketUser newUser)
|
||||
{
|
||||
await _userRepository.Update(newUser);
|
||||
}
|
||||
|
||||
public async Task UserLeft(SocketGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g =>
|
||||
g.GuildId.Equals(user.Guild.Id.AsLong()));
|
||||
if (guild?.ShowLeave ?? false)
|
||||
{
|
||||
var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(guild.ModChannel.AsUlong());
|
||||
await modChannelSocket.SendMessageAsync($"{user.Username}#{user.Discriminator} left the server");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send leave message", e);
|
||||
}
|
||||
|
||||
_logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||
}
|
||||
|
||||
//
|
||||
// Message Stuff
|
||||
//
|
||||
|
||||
public async Task MessageDeleted(Cacheable<IMessage, ulong> message, ISocketMessageChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guildSocketData = ((IGuildChannel) channel).Guild;
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildSocketData.Id.AsLong()));
|
||||
if ((guild?.ShowDelete ?? false) && guild?.ModChannel != 0)
|
||||
{
|
||||
var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(guild.ModChannel.AsUlong());
|
||||
var sb = new StringBuilder();
|
||||
if (message.Value != null)
|
||||
{
|
||||
sb.AppendLine($"The following message from {message.Value.Author.Username}#{message.Value.Author.Discriminator} was deleted in <#{channel.Id}>");
|
||||
sb.AppendLine(message.Value.Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine("Someone deleted a message, the message was not cached...");
|
||||
}
|
||||
|
||||
await modChannelSocket.SendMessageAsync(sb.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send delete message...", e);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Reactions
|
||||
//
|
||||
|
||||
public Task ReactionAdded(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||
{
|
||||
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||
_reactionListener.GiveRole(socketMessageChannel, reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task ReactionRemoved(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||
{
|
||||
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||
_reactionListener.RemoveRole(socketMessageChannel, reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
117
Geekbot.net/Handlers/CommandHandler.cs
Normal file
117
Geekbot.net/Handlers/CommandHandler.cs
Normal file
|
@ -0,0 +1,117 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Commands;
|
||||
using Discord.Rest;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
|
||||
namespace Geekbot.net.Handlers
|
||||
{
|
||||
public class CommandHandler
|
||||
{
|
||||
private readonly IDiscordClient _client;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly IServiceProvider _servicesProvider;
|
||||
private readonly CommandService _commands;
|
||||
private readonly RestApplication _applicationInfo;
|
||||
private readonly List<ulong> _ignoredServers;
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
public CommandHandler(DatabaseContext database, IDiscordClient client, IGeekbotLogger logger, IServiceProvider servicesProvider, CommandService commands, RestApplication applicationInfo)
|
||||
{
|
||||
_database = database;
|
||||
_client = client;
|
||||
_logger = logger;
|
||||
_servicesProvider = servicesProvider;
|
||||
_commands = commands;
|
||||
_applicationInfo = applicationInfo;
|
||||
|
||||
// Some guilds only want very specific functionally without any of the commands, a quick hack that solves that "short term"
|
||||
// ToDo: create a clean solution for this...
|
||||
_ignoredServers = new List<ulong>
|
||||
{
|
||||
228623803201224704, // SwitzerLAN
|
||||
169844523181015040, // EEvent
|
||||
248531441548263425, // MYI
|
||||
110373943822540800 // Discord Bots
|
||||
};
|
||||
}
|
||||
|
||||
public Task RunCommand(SocketMessage messageParam)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!(messageParam is SocketUserMessage message)) return Task.CompletedTask;
|
||||
if (message.Author.IsBot) return Task.CompletedTask;
|
||||
|
||||
var guildId = ((SocketGuildChannel) message.Channel).Guild.Id;
|
||||
if (IsIgnoredGuild(guildId, message.Author.Id)) return Task.CompletedTask;
|
||||
|
||||
var lowCaseMsg = message.ToString().ToLower();
|
||||
if (ShouldHui(lowCaseMsg, guildId))
|
||||
{
|
||||
message.Channel.SendMessageAsync("hui!!!");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
if (ShouldPong(lowCaseMsg, guildId))
|
||||
{
|
||||
message.Channel.SendMessageAsync("pong");
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
var argPos = 0;
|
||||
if (!IsCommand(message, ref argPos)) return Task.CompletedTask;
|
||||
|
||||
ExecuteCommand(message, argPos);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to Process Message", e);
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void ExecuteCommand(IUserMessage message, int argPos)
|
||||
{
|
||||
var context = new CommandContext(_client, message);
|
||||
_commands.ExecuteAsync(context, argPos, _servicesProvider);
|
||||
_logger.Information(LogSource.Command, context.Message.Content.Split(" ")[0].Replace("!", ""), SimpleConextConverter.ConvertContext(context));
|
||||
}
|
||||
|
||||
private bool IsIgnoredGuild(ulong guildId, ulong authorId)
|
||||
{
|
||||
if (!_ignoredServers.Contains(guildId)) return false;
|
||||
return authorId == _applicationInfo.Owner.Id;
|
||||
}
|
||||
|
||||
private bool IsCommand(IUserMessage message, ref int argPos)
|
||||
{
|
||||
return message.HasCharPrefix('!', ref argPos) || message.HasMentionPrefix(_client.CurrentUser, ref argPos);
|
||||
}
|
||||
|
||||
private bool ShouldPong(string lowerCaseMessage, ulong guildId)
|
||||
{
|
||||
if (!lowerCaseMessage.StartsWith("ping ") && !lowerCaseMessage.Equals("ping")) return false;
|
||||
return GetGuildSettings(guildId)?.Ping ?? false;
|
||||
}
|
||||
|
||||
private bool ShouldHui(string lowerCaseMessage, ulong guildId)
|
||||
{
|
||||
if (!lowerCaseMessage.StartsWith("hui")) return false;
|
||||
return GetGuildSettings(guildId)?.Hui ?? false;
|
||||
}
|
||||
|
||||
private GuildSettingsModel GetGuildSettings(ulong guildId)
|
||||
{
|
||||
return _database.GuildSettings.FirstOrDefault(guild => guild.GuildId.Equals(guildId.AsLong()));
|
||||
}
|
||||
}
|
||||
}
|
55
Geekbot.net/Handlers/MessageDeletedHandler.cs
Normal file
55
Geekbot.net/Handlers/MessageDeletedHandler.cs
Normal file
|
@ -0,0 +1,55 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
|
||||
namespace Geekbot.net.Handlers
|
||||
{
|
||||
public class MessageDeletedHandler
|
||||
{
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly IDiscordClient _client;
|
||||
|
||||
public MessageDeletedHandler(DatabaseContext database, IGeekbotLogger logger, IDiscordClient client)
|
||||
{
|
||||
_database = database;
|
||||
_logger = logger;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task HandleMessageDeleted(Cacheable<IMessage, ulong> message, ISocketMessageChannel channel)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guildSocketData = ((IGuildChannel) channel).Guild;
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(guildSocketData.Id.AsLong()));
|
||||
if ((guild?.ShowDelete ?? false) && guild?.ModChannel != 0)
|
||||
{
|
||||
var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(guild.ModChannel.AsUlong());
|
||||
var sb = new StringBuilder();
|
||||
if (message.Value != null)
|
||||
{
|
||||
sb.AppendLine($"The following message from {message.Value.Author.Username}#{message.Value.Author.Discriminator} was deleted in <#{channel.Id}>");
|
||||
sb.AppendLine(message.Value.Content);
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendLine("Someone deleted a message, the message was not cached...");
|
||||
}
|
||||
|
||||
await modChannelSocket.SendMessageAsync(sb.ToString());
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send delete message...", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
33
Geekbot.net/Handlers/ReactionHandler.cs
Normal file
33
Geekbot.net/Handlers/ReactionHandler.cs
Normal file
|
@ -0,0 +1,33 @@
|
|||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Lib.ReactionListener;
|
||||
|
||||
namespace Geekbot.net.Handlers
|
||||
{
|
||||
public class ReactionHandler
|
||||
{
|
||||
private readonly IReactionListener _reactionListener;
|
||||
|
||||
public ReactionHandler(IReactionListener reactionListener)
|
||||
{
|
||||
_reactionListener = reactionListener;
|
||||
}
|
||||
|
||||
public Task Added(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||
{
|
||||
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||
_reactionListener.GiveRole(socketMessageChannel, reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task Removed(Cacheable<IUserMessage, ulong> cacheable, ISocketMessageChannel socketMessageChannel, SocketReaction reaction)
|
||||
{
|
||||
if (reaction.User.Value.IsBot) return Task.CompletedTask;
|
||||
if (!_reactionListener.IsListener(reaction.MessageId)) return Task.CompletedTask;
|
||||
_reactionListener.RemoveRole(socketMessageChannel, reaction);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
62
Geekbot.net/Handlers/StatsHandler.cs
Normal file
62
Geekbot.net/Handlers/StatsHandler.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Database.Models;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace Geekbot.net.Handlers
|
||||
{
|
||||
public class StatsHandler
|
||||
{
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly DatabaseContext _database;
|
||||
|
||||
public StatsHandler(IGeekbotLogger logger, DatabaseContext database)
|
||||
{
|
||||
_logger = logger;
|
||||
_database = database;
|
||||
}
|
||||
|
||||
public async Task UpdateStats(SocketMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (message == null) return;
|
||||
if (message.Channel.Name.StartsWith('@'))
|
||||
{
|
||||
_logger.Information(LogSource.Message, $"[DM-Channel] {message.Content}", SimpleConextConverter.ConvertSocketMessage(message, true));
|
||||
return;
|
||||
}
|
||||
|
||||
var channel = (SocketGuildChannel) message.Channel;
|
||||
|
||||
var rowId = await _database.Database.ExecuteSqlRawAsync(
|
||||
"UPDATE \"Messages\" SET \"MessageCount\" = \"MessageCount\" + 1 WHERE \"GuildId\" = {0} AND \"UserId\" = {1}",
|
||||
channel.Guild.Id.AsLong(),
|
||||
message.Author.Id.AsLong()
|
||||
);
|
||||
|
||||
if (rowId == 0)
|
||||
{
|
||||
await _database.Messages.AddAsync(new MessagesModel
|
||||
{
|
||||
UserId = message.Author.Id.AsLong(),
|
||||
GuildId = channel.Guild.Id.AsLong(),
|
||||
MessageCount = 1
|
||||
});
|
||||
await _database.SaveChangesAsync();
|
||||
}
|
||||
|
||||
if (message.Author.IsBot) return;
|
||||
_logger.Information(LogSource.Message, message.Content, SimpleConextConverter.ConvertSocketMessage(message));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Message, "Could not process message stats", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
96
Geekbot.net/Handlers/UserHandler.cs
Normal file
96
Geekbot.net/Handlers/UserHandler.cs
Normal file
|
@ -0,0 +1,96 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Discord;
|
||||
using Discord.Rest;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Lib.Extensions;
|
||||
using Geekbot.net.Lib.Logger;
|
||||
using Geekbot.net.Lib.UserRepository;
|
||||
|
||||
namespace Geekbot.net.Handlers
|
||||
{
|
||||
public class UserHandler
|
||||
{
|
||||
private readonly IUserRepository _userRepository;
|
||||
private readonly IGeekbotLogger _logger;
|
||||
private readonly DatabaseContext _database;
|
||||
private readonly IDiscordClient _client;
|
||||
|
||||
public UserHandler(IUserRepository userRepository, IGeekbotLogger logger, DatabaseContext database, IDiscordClient client)
|
||||
{
|
||||
_userRepository = userRepository;
|
||||
_logger = logger;
|
||||
_database = database;
|
||||
_client = client;
|
||||
}
|
||||
|
||||
public async Task Joined(SocketGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var userRepoUpdate = _userRepository.Update(user);
|
||||
_logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||
|
||||
if (!user.IsBot)
|
||||
{
|
||||
var guildSettings = _database.GuildSettings.FirstOrDefault(guild => guild.GuildId == user.Guild.Id.AsLong());
|
||||
var message = guildSettings?.WelcomeMessage;
|
||||
if (string.IsNullOrEmpty(message)) return;
|
||||
message = message.Replace("$user", user.Mention);
|
||||
|
||||
var fallbackSender = new Func<Task<RestUserMessage>>(() => user.Guild.DefaultChannel.SendMessageAsync(message));
|
||||
if (guildSettings.WelcomeChannel != 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
var target = await _client.GetChannelAsync(guildSettings.WelcomeChannel.AsUlong());
|
||||
var channel = target as ISocketMessageChannel;
|
||||
await channel.SendMessageAsync(message);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send welcome message to user defined welcome channel", e);
|
||||
await fallbackSender();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
await fallbackSender();
|
||||
}
|
||||
}
|
||||
|
||||
await userRepoUpdate;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send welcome message", e);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task Updated(SocketUser oldUser, SocketUser newUser)
|
||||
{
|
||||
await _userRepository.Update(newUser);
|
||||
}
|
||||
|
||||
public async Task Left(SocketGuildUser user)
|
||||
{
|
||||
try
|
||||
{
|
||||
var guild = _database.GuildSettings.FirstOrDefault(g => g.GuildId.Equals(user.Guild.Id.AsLong()));
|
||||
if (guild?.ShowLeave ?? false)
|
||||
{
|
||||
var modChannelSocket = (ISocketMessageChannel) await _client.GetChannelAsync(guild.ModChannel.AsUlong());
|
||||
await modChannelSocket.SendMessageAsync($"{user.Username}#{user.Discriminator} left the server");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Error(LogSource.Geekbot, "Failed to send leave message", e);
|
||||
}
|
||||
|
||||
_logger.Information(LogSource.Geekbot, $"{user.Username} ({user.Id}) joined {user.Guild.Name} ({user.Guild.Id})");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,7 +11,7 @@ namespace Geekbot.net.Lib.Logger
|
|||
{
|
||||
Message = new MessageDto.MessageContent
|
||||
{
|
||||
Content = context.Message.Content,
|
||||
Content = context.Message.Content, // Only when an error occurs, including for diagnostic reason
|
||||
Id = context.Message.Id.ToString(),
|
||||
Attachments = context.Message.Attachments.Count,
|
||||
ChannelMentions = context.Message.MentionedChannelIds.Count,
|
||||
|
@ -42,7 +42,6 @@ namespace Geekbot.net.Lib.Logger
|
|||
{
|
||||
Message = new MessageDto.MessageContent
|
||||
{
|
||||
Content = message.Content,
|
||||
Id = message.Id.ToString(),
|
||||
Attachments = message.Attachments.Count,
|
||||
ChannelMentions = message.MentionedChannels.Count,
|
||||
|
|
|
@ -7,6 +7,7 @@ using Discord;
|
|||
using Discord.Commands;
|
||||
using Discord.WebSocket;
|
||||
using Geekbot.net.Database;
|
||||
using Geekbot.net.Handlers;
|
||||
using Geekbot.net.Lib;
|
||||
using Geekbot.net.Lib.Clients;
|
||||
using Geekbot.net.Lib.Converters;
|
||||
|
@ -34,12 +35,11 @@ namespace Geekbot.net
|
|||
private CommandService _commands;
|
||||
private DatabaseInitializer _databaseInitializer;
|
||||
private IGlobalSettings _globalSettings;
|
||||
private IServiceCollection _services;
|
||||
private IServiceProvider _servicesProvider;
|
||||
private string _token;
|
||||
private GeekbotLogger _logger;
|
||||
private IUserRepository _userRepository;
|
||||
private RunParameters _runParameters;
|
||||
private IReactionListener _reactionListener;
|
||||
|
||||
private static void Main(string[] args)
|
||||
{
|
||||
|
@ -73,66 +73,25 @@ namespace Geekbot.net
|
|||
{
|
||||
_logger = logger;
|
||||
_runParameters = runParameters;
|
||||
logger.Information(LogSource.Geekbot, "Initing Stuff");
|
||||
var discordLogger = new DiscordLogger(logger);
|
||||
|
||||
_client = new DiscordSocketClient(new DiscordSocketConfig
|
||||
{
|
||||
LogLevel = LogSeverity.Verbose,
|
||||
MessageCacheSize = 1000,
|
||||
ExclusiveBulkDelete = true
|
||||
});
|
||||
_client.Log += discordLogger.Log;
|
||||
_commands = new CommandService();
|
||||
|
||||
_databaseInitializer = new DatabaseInitializer(runParameters, logger);
|
||||
var database = _databaseInitializer.Initialize();
|
||||
database.Database.EnsureCreated();
|
||||
if(!_runParameters.InMemory) database.Database.Migrate();
|
||||
|
||||
logger.Information(LogSource.Geekbot, "Connecting to Database");
|
||||
var database = ConnectToDatabase();
|
||||
_globalSettings = new GlobalSettings(database);
|
||||
|
||||
_token = runParameters.Token ?? _globalSettings.GetKey("DiscordToken");
|
||||
if (string.IsNullOrEmpty(_token))
|
||||
{
|
||||
Console.Write("Your bot Token: ");
|
||||
var newToken = Console.ReadLine();
|
||||
await _globalSettings.SetKey("DiscordToken", newToken);
|
||||
await _globalSettings.SetKey("Game", "Ping Pong");
|
||||
_token = newToken;
|
||||
}
|
||||
|
||||
_services = new ServiceCollection();
|
||||
|
||||
_userRepository = new UserRepository(_databaseInitializer.Initialize(), logger);
|
||||
var fortunes = new FortunesProvider(logger);
|
||||
var mediaProvider = new MediaProvider(logger);
|
||||
var malClient = new MalClient(_globalSettings, logger);
|
||||
var levelCalc = new LevelCalc();
|
||||
var emojiConverter = new EmojiConverter();
|
||||
var mtgManaConverter = new MtgManaConverter();
|
||||
var wikipediaClient = new WikipediaClient();
|
||||
var randomNumberGenerator = new RandomNumberGenerator();
|
||||
var kvMemoryStore = new KvInInMemoryStore();
|
||||
|
||||
_services.AddSingleton(_userRepository);
|
||||
_services.AddSingleton<IGeekbotLogger>(logger);
|
||||
_services.AddSingleton<ILevelCalc>(levelCalc);
|
||||
_services.AddSingleton<IEmojiConverter>(emojiConverter);
|
||||
_services.AddSingleton<IFortunesProvider>(fortunes);
|
||||
_services.AddSingleton<IMediaProvider>(mediaProvider);
|
||||
_services.AddSingleton<IMalClient>(malClient);
|
||||
_services.AddSingleton<IMtgManaConverter>(mtgManaConverter);
|
||||
_services.AddSingleton<IWikipediaClient>(wikipediaClient);
|
||||
_services.AddSingleton<IRandomNumberGenerator>(randomNumberGenerator);
|
||||
_services.AddSingleton<IKvInMemoryStore>(kvMemoryStore);
|
||||
_services.AddSingleton(_globalSettings);
|
||||
_services.AddTransient<IHighscoreManager>(e => new HighscoreManager(_databaseInitializer.Initialize(), _userRepository));
|
||||
_services.AddTransient(e => _databaseInitializer.Initialize());
|
||||
|
||||
logger.Information(LogSource.Geekbot, "Connecting to Discord");
|
||||
|
||||
SetupDiscordClient();
|
||||
await Login();
|
||||
_logger.Information(LogSource.Geekbot, $"Now Connected as {_client.CurrentUser.Username} to {_client.Guilds.Count} Servers");
|
||||
await _client.SetGameAsync(_globalSettings.GetKey("Game"));
|
||||
|
||||
_logger.Information(LogSource.Geekbot, "Loading Dependencies and Handlers");
|
||||
RegisterDependencies();
|
||||
await RegisterHandlers();
|
||||
|
||||
_logger.Information(LogSource.Api, "Starting Web API");
|
||||
StartWebApi();
|
||||
|
||||
_logger.Information(LogSource.Geekbot, "Done and ready for use");
|
||||
|
||||
await Task.Delay(-1);
|
||||
}
|
||||
|
@ -141,42 +100,10 @@ namespace Geekbot.net
|
|||
{
|
||||
try
|
||||
{
|
||||
await _client.LoginAsync(TokenType.Bot, _token);
|
||||
var token = await GetToken();
|
||||
await _client.LoginAsync(TokenType.Bot, token);
|
||||
await _client.StartAsync();
|
||||
var isConneted = await IsConnected();
|
||||
if (isConneted)
|
||||
{
|
||||
var applicationInfo = await _client.GetApplicationInfoAsync();
|
||||
await _client.SetGameAsync(_globalSettings.GetKey("Game"));
|
||||
_logger.Information(LogSource.Geekbot, $"Now Connected as {_client.CurrentUser.Username} to {_client.Guilds.Count} Servers");
|
||||
|
||||
_logger.Information(LogSource.Geekbot, "Registering Stuff");
|
||||
var translationHandler = new TranslationHandler(_databaseInitializer.Initialize(), _logger);
|
||||
var errorHandler = new ErrorHandler(_logger, translationHandler, _runParameters.ExposeErrors);
|
||||
var reactionListener = new ReactionListener(_databaseInitializer.Initialize());
|
||||
_services.AddSingleton<IErrorHandler>(errorHandler);
|
||||
_services.AddSingleton<ITranslationHandler>(translationHandler);
|
||||
_services.AddSingleton(_client);
|
||||
_services.AddSingleton<IReactionListener>(reactionListener);
|
||||
_servicesProvider = _services.BuildServiceProvider();
|
||||
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _servicesProvider);
|
||||
|
||||
var handlers = new Handlers(_databaseInitializer, _client, _logger, _servicesProvider, _commands, _userRepository, reactionListener, applicationInfo);
|
||||
|
||||
_client.MessageReceived += handlers.RunCommand;
|
||||
_client.MessageDeleted += handlers.MessageDeleted;
|
||||
_client.UserJoined += handlers.UserJoined;
|
||||
_client.UserUpdated += handlers.UserUpdated;
|
||||
_client.UserLeft += handlers.UserLeft;
|
||||
_client.ReactionAdded += handlers.ReactionAdded;
|
||||
_client.ReactionRemoved += handlers.ReactionRemoved;
|
||||
if (!_runParameters.InMemory) _client.MessageReceived += handlers.UpdateStats;
|
||||
|
||||
var webserver = _runParameters.DisableApi ? Task.Delay(10) : StartWebApi();
|
||||
_logger.Information(LogSource.Geekbot, "Done and ready for use");
|
||||
|
||||
await webserver;
|
||||
}
|
||||
while (!_client.ConnectionState.Equals(ConnectionState.Connected)) await Task.Delay(25);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -185,19 +112,117 @@ namespace Geekbot.net
|
|||
}
|
||||
}
|
||||
|
||||
private async Task<bool> IsConnected()
|
||||
private DatabaseContext ConnectToDatabase()
|
||||
{
|
||||
while (!_client.ConnectionState.Equals(ConnectionState.Connected))
|
||||
await Task.Delay(25);
|
||||
return true;
|
||||
_databaseInitializer = new DatabaseInitializer(_runParameters, _logger);
|
||||
var database = _databaseInitializer.Initialize();
|
||||
database.Database.EnsureCreated();
|
||||
if(!_runParameters.InMemory) database.Database.Migrate();
|
||||
|
||||
return database;
|
||||
}
|
||||
|
||||
private Task StartWebApi()
|
||||
private async Task<string> GetToken()
|
||||
{
|
||||
_logger.Information(LogSource.Api, "Starting Webserver");
|
||||
var token = _runParameters.Token ?? _globalSettings.GetKey("DiscordToken");
|
||||
if (string.IsNullOrEmpty(token))
|
||||
{
|
||||
Console.Write("Your bot Token: ");
|
||||
var newToken = Console.ReadLine();
|
||||
await _globalSettings.SetKey("DiscordToken", newToken);
|
||||
await _globalSettings.SetKey("Game", "Ping Pong");
|
||||
token = newToken;
|
||||
}
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
private void SetupDiscordClient()
|
||||
{
|
||||
_client = new DiscordSocketClient(new DiscordSocketConfig
|
||||
{
|
||||
LogLevel = LogSeverity.Verbose,
|
||||
MessageCacheSize = 1000,
|
||||
ExclusiveBulkDelete = true
|
||||
});
|
||||
|
||||
var discordLogger = new DiscordLogger(_logger);
|
||||
_client.Log += discordLogger.Log;
|
||||
}
|
||||
|
||||
private void RegisterDependencies()
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
|
||||
_userRepository = new UserRepository(_databaseInitializer.Initialize(), _logger);
|
||||
_reactionListener = new ReactionListener(_databaseInitializer.Initialize());
|
||||
var fortunes = new FortunesProvider(_logger);
|
||||
var mediaProvider = new MediaProvider(_logger);
|
||||
var malClient = new MalClient(_globalSettings, _logger);
|
||||
var levelCalc = new LevelCalc();
|
||||
var emojiConverter = new EmojiConverter();
|
||||
var mtgManaConverter = new MtgManaConverter();
|
||||
var wikipediaClient = new WikipediaClient();
|
||||
var randomNumberGenerator = new RandomNumberGenerator();
|
||||
var kvMemoryStore = new KvInInMemoryStore();
|
||||
var translationHandler = new TranslationHandler(_databaseInitializer.Initialize(), _logger);
|
||||
var errorHandler = new ErrorHandler(_logger, translationHandler, _runParameters.ExposeErrors);
|
||||
|
||||
services.AddSingleton(_userRepository);
|
||||
services.AddSingleton<IGeekbotLogger>(_logger);
|
||||
services.AddSingleton<ILevelCalc>(levelCalc);
|
||||
services.AddSingleton<IEmojiConverter>(emojiConverter);
|
||||
services.AddSingleton<IFortunesProvider>(fortunes);
|
||||
services.AddSingleton<IMediaProvider>(mediaProvider);
|
||||
services.AddSingleton<IMalClient>(malClient);
|
||||
services.AddSingleton<IMtgManaConverter>(mtgManaConverter);
|
||||
services.AddSingleton<IWikipediaClient>(wikipediaClient);
|
||||
services.AddSingleton<IRandomNumberGenerator>(randomNumberGenerator);
|
||||
services.AddSingleton<IKvInMemoryStore>(kvMemoryStore);
|
||||
services.AddSingleton<IGlobalSettings>(_globalSettings);
|
||||
services.AddSingleton<IErrorHandler>(errorHandler);
|
||||
services.AddSingleton<ITranslationHandler>(translationHandler);
|
||||
services.AddSingleton<IReactionListener>(_reactionListener);
|
||||
services.AddSingleton(_client);
|
||||
services.AddTransient<IHighscoreManager>(e => new HighscoreManager(_databaseInitializer.Initialize(), _userRepository));
|
||||
services.AddTransient(e => _databaseInitializer.Initialize());
|
||||
|
||||
_servicesProvider = services.BuildServiceProvider();
|
||||
}
|
||||
|
||||
private async Task RegisterHandlers()
|
||||
{
|
||||
var applicationInfo = await _client.GetApplicationInfoAsync();
|
||||
|
||||
_commands = new CommandService();
|
||||
await _commands.AddModulesAsync(Assembly.GetEntryAssembly(), _servicesProvider);
|
||||
|
||||
var commandHandler = new CommandHandler(_databaseInitializer.Initialize(), _client, _logger, _servicesProvider, _commands, applicationInfo);
|
||||
var userHandler = new UserHandler(_userRepository, _logger, _databaseInitializer.Initialize(), _client);
|
||||
var reactionHandler = new ReactionHandler(_reactionListener);
|
||||
var statsHandler = new StatsHandler(_logger, _databaseInitializer.Initialize());
|
||||
var messageDeletedHandler = new MessageDeletedHandler(_databaseInitializer.Initialize(), _logger, _client);
|
||||
|
||||
_client.MessageReceived += commandHandler.RunCommand;
|
||||
_client.MessageDeleted += messageDeletedHandler.HandleMessageDeleted;
|
||||
_client.UserJoined += userHandler.Joined;
|
||||
_client.UserUpdated += userHandler.Updated;
|
||||
_client.UserLeft += userHandler.Left;
|
||||
_client.ReactionAdded += reactionHandler.Added;
|
||||
_client.ReactionRemoved += reactionHandler.Removed;
|
||||
if (!_runParameters.InMemory) _client.MessageReceived += statsHandler.UpdateStats;
|
||||
}
|
||||
|
||||
private void StartWebApi()
|
||||
{
|
||||
if (_runParameters.DisableApi)
|
||||
{
|
||||
_logger.Warning(LogSource.Api, "Web API is disabled");
|
||||
return;
|
||||
}
|
||||
|
||||
var highscoreManager = new HighscoreManager(_databaseInitializer.Initialize(), _userRepository);
|
||||
WebApiStartup.StartWebApi(_logger, _runParameters, _commands, _databaseInitializer.Initialize(), _client, _globalSettings, highscoreManager);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue