Add preliminary Sentry support

This commit is contained in:
Ske 2019-07-15 21:02:50 +02:00
parent 39152dbd27
commit 18e4d7c9ac
3 changed files with 72 additions and 40 deletions

View File

@ -16,6 +16,8 @@ using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
using NodaTime; using NodaTime;
using Npgsql; using Npgsql;
using Sentry;
using Sentry.Extensibility;
namespace PluralKit.Bot namespace PluralKit.Bot
{ {
@ -33,19 +35,26 @@ namespace PluralKit.Bot
using (var services = BuildServiceProvider()) using (var services = BuildServiceProvider())
{ {
Console.WriteLine("- Connecting to database..."); var coreConfig = services.GetRequiredService<CoreConfig>();
using (var conn = await services.GetRequiredService<DbConnectionFactory>().Obtain()) var botConfig = services.GetRequiredService<BotConfig>();
await Schema.CreateTables(conn);
Console.WriteLine("- Connecting to Discord..."); using (SentrySdk.Init(coreConfig.SentryUrl))
var client = services.GetRequiredService<IDiscordClient>() as DiscordShardedClient; {
await client.LoginAsync(TokenType.Bot, services.GetRequiredService<BotConfig>().Token);
await client.StartAsync();
Console.WriteLine("- Initializing bot..."); Console.WriteLine("- Connecting to database...");
await services.GetRequiredService<Bot>().Init(); using (var conn = await services.GetRequiredService<DbConnectionFactory>().Obtain())
await Schema.CreateTables(conn);
await Task.Delay(-1);
Console.WriteLine("- Connecting to Discord...");
var client = services.GetRequiredService<IDiscordClient>() as DiscordShardedClient;
await client.LoginAsync(TokenType.Bot, botConfig.Token);
await client.StartAsync();
Console.WriteLine("- Initializing bot...");
await services.GetRequiredService<Bot>().Init();
await Task.Delay(-1);
}
} }
} }
@ -82,6 +91,8 @@ namespace PluralKit.Bot
.AddTransient<MemberStore>() .AddTransient<MemberStore>()
.AddTransient<MessageStore>() .AddTransient<MessageStore>()
.AddTransient<SwitchStore>() .AddTransient<SwitchStore>()
.AddScoped<IHub>(_ => HubAdapter.Instance)
.BuildServiceProvider(); .BuildServiceProvider();
} }
class Bot class Bot
@ -91,13 +102,15 @@ namespace PluralKit.Bot
private CommandService _commands; private CommandService _commands;
private ProxyService _proxy; private ProxyService _proxy;
private Timer _updateTimer; private Timer _updateTimer;
private IHub _hub;
public Bot(IServiceProvider services, IDiscordClient client, CommandService commands, ProxyService proxy) public Bot(IServiceProvider services, IDiscordClient client, CommandService commands, ProxyService proxy, IHub hub)
{ {
this._services = services; this._services = services;
this._client = client as DiscordShardedClient; this._client = client as DiscordShardedClient;
this._commands = commands; this._commands = commands;
this._proxy = proxy; this._proxy = proxy;
_hub = hub;
} }
public async Task Init() public async Task Init()
@ -158,40 +171,57 @@ namespace PluralKit.Bot
private async Task MessageReceived(SocketMessage _arg) private async Task MessageReceived(SocketMessage _arg)
{ {
var serviceScope = _services.CreateScope(); using (SentrySdk.PushScope())
using (var serviceScope = _services.CreateScope())
// Ignore system messages (member joined, message pinned, etc)
var arg = _arg as SocketUserMessage;
if (arg == null) return;
// Ignore bot messages
if (arg.Author.IsBot || arg.Author.IsWebhook) return;
int argPos = 0;
// Check if message starts with the command prefix
if (arg.HasStringPrefix("pk;", ref argPos, StringComparison.OrdinalIgnoreCase) || arg.HasStringPrefix("pk!", ref argPos, StringComparison.OrdinalIgnoreCase) || arg.HasMentionPrefix(_client.CurrentUser, ref argPos))
{ {
// Essentially move the argPos pointer by however much whitespace is at the start of the post-argPos string SentrySdk.AddBreadcrumb("event.message", data: new Dictionary<string, string>()
var trimStartLengthDiff = arg.Content.Substring(argPos).Length - arg.Content.Substring(argPos).TrimStart().Length; {
argPos += trimStartLengthDiff; {"content", _arg.Content},
{"user", _arg.Author.Id.ToString()},
// If it does, fetch the sender's system (because most commands need that) into the context, {"channel", _arg.Channel.Id.ToString()},
// and start command execution {"guild", ((_arg.Channel as IGuildChannel)?.GuildId ?? 0).ToString()}
// Note system may be null if user has no system, hence `OrDefault` });
PKSystem system;
using (var conn = await serviceScope.ServiceProvider.GetService<DbConnectionFactory>().Obtain()) // Ignore system messages (member joined, message pinned, etc)
system = await conn.QueryFirstOrDefaultAsync<PKSystem>("select systems.* from systems, accounts where accounts.uid = @Id and systems.id = accounts.system", new { Id = arg.Author.Id }); var arg = _arg as SocketUserMessage;
await _commands.ExecuteAsync(new PKCommandContext(_client, arg, system), argPos, serviceScope.ServiceProvider); if (arg == null) return;
}
else // Ignore bot messages
{ if (arg.Author.IsBot || arg.Author.IsWebhook) return;
// If not, try proxying anyway
await _proxy.HandleMessageAsync(arg); int argPos = 0;
// Check if message starts with the command prefix
if (arg.HasStringPrefix("pk;", ref argPos, StringComparison.OrdinalIgnoreCase) ||
arg.HasStringPrefix("pk!", ref argPos, StringComparison.OrdinalIgnoreCase) ||
arg.HasMentionPrefix(_client.CurrentUser, ref argPos))
{
// Essentially move the argPos pointer by however much whitespace is at the start of the post-argPos string
var trimStartLengthDiff = arg.Content.Substring(argPos).Length -
arg.Content.Substring(argPos).TrimStart().Length;
argPos += trimStartLengthDiff;
// If it does, fetch the sender's system (because most commands need that) into the context,
// and start command execution
// Note system may be null if user has no system, hence `OrDefault`
PKSystem system;
using (var conn = await serviceScope.ServiceProvider.GetService<DbConnectionFactory>().Obtain())
system = await conn.QueryFirstOrDefaultAsync<PKSystem>(
"select systems.* from systems, accounts where accounts.uid = @Id and systems.id = accounts.system",
new {Id = arg.Author.Id});
await _commands.ExecuteAsync(new PKCommandContext(_client, arg, system), argPos,
serviceScope.ServiceProvider);
}
else
{
// If not, try proxying anyway
await _proxy.HandleMessageAsync(arg);
}
} }
} }
private void HandleRuntimeError(Exception e) private void HandleRuntimeError(Exception e)
{ {
SentrySdk.CaptureException(e);
Console.Error.WriteLine(e); Console.Error.WriteLine(e);
} }
} }

View File

@ -14,6 +14,7 @@
<PackageReference Include="Discord.Net.Webhook" Version="2.0.1" /> <PackageReference Include="Discord.Net.Webhook" Version="2.0.1" />
<PackageReference Include="Discord.Net.WebSocket" Version="2.0.1" /> <PackageReference Include="Discord.Net.WebSocket" Version="2.0.1" />
<PackageReference Include="Humanizer.Core" Version="2.6.2" /> <PackageReference Include="Humanizer.Core" Version="2.6.2" />
<PackageReference Include="Sentry" Version="2.0.0-beta2" />
<PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0006" /> <PackageReference Include="SixLabors.ImageSharp" Version="1.0.0-beta0006" />
</ItemGroup> </ItemGroup>

View File

@ -3,5 +3,6 @@ namespace PluralKit
public class CoreConfig public class CoreConfig
{ {
public string Database { get; set; } public string Database { get; set; }
public string SentryUrl { get; set; }
} }
} }