diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 0000000..807df2c --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,14 @@ + + + + net9.0 + enable + enable + latest + All + true + true + true + + + diff --git a/src/StevesBot.Worker.Tests/.editorconfig b/src/StevesBot.Worker.Tests/.editorconfig new file mode 100644 index 0000000..a84e56b --- /dev/null +++ b/src/StevesBot.Worker.Tests/.editorconfig @@ -0,0 +1,4 @@ +[*.cs] +dotnet_diagnostic.CA1515.severity = none +dotnet_diagnostic.CA1707.severity = none +dotnet_diagnostic.CA2201.severity = none diff --git a/src/StevesBot.Worker.Tests/StevesBot.Worker.Tests.csproj b/src/StevesBot.Worker.Tests/StevesBot.Worker.Tests.csproj index 38c5bc8..3602d53 100644 --- a/src/StevesBot.Worker.Tests/StevesBot.Worker.Tests.csproj +++ b/src/StevesBot.Worker.Tests/StevesBot.Worker.Tests.csproj @@ -1,21 +1,41 @@ - + - net9.0 - enable - enable false - - - - + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + + + true + ./TestResults/Coverage/ + cobertura + [StevesBot.Worker]* + **/Program.cs,**/Worker.cs + + + + + + + diff --git a/src/StevesBot.Worker.Tests/Unit/DiscordClientExceptionTests.cs b/src/StevesBot.Worker.Tests/Unit/DiscordClientExceptionTests.cs new file mode 100644 index 0000000..6be76d7 --- /dev/null +++ b/src/StevesBot.Worker.Tests/Unit/DiscordClientExceptionTests.cs @@ -0,0 +1,37 @@ +namespace StevesBot.Worker.Tests.Unit; + +public class DiscordClientExceptionTests +{ + [Fact] + public void Constructor_WhenCalledWithoutParameters_ItShouldCreateInstance() + { + var exception = new DiscordClientException(); + + exception.Should().NotBeNull(); + exception.Should().BeOfType(); + } + + [Fact] + public void Constructor_WhenCalledWithMessage_ItShouldCreateInstance() + { + var message = "Test message"; + var exception = new DiscordClientException(message); + + exception.Should().NotBeNull(); + exception.Should().BeOfType(); + exception.Message.Should().Be(message); + } + + [Fact] + public void Constructor_WhenCalledWithMessageAndInnerException_ItShouldCreateInstance() + { + var message = "Test message"; + var innerException = new Exception("Inner exception"); + var exception = new DiscordClientException(message, innerException); + + exception.Should().NotBeNull(); + exception.Should().BeOfType(); + exception.Message.Should().Be(message); + exception.InnerException.Should().Be(innerException); + } +} \ No newline at end of file diff --git a/src/StevesBot.Worker.Tests/Unit/DiscordClientOptionsTests.cs b/src/StevesBot.Worker.Tests/Unit/DiscordClientOptionsTests.cs new file mode 100644 index 0000000..cd2f5c5 --- /dev/null +++ b/src/StevesBot.Worker.Tests/Unit/DiscordClientOptionsTests.cs @@ -0,0 +1,37 @@ +namespace StevesBot.Worker.Tests.Unit; + +public class DiscordClientOptionsTests +{ + [Fact] + public void Constructor_WhenCalledWithoutParameters_ItShouldCreateInstance() + { + var options = new DiscordClientOptions(); + + options.Should().NotBeNull(); + options.Should().BeOfType(); + options.ApiUrl.Should().Be(string.Empty); + options.AppToken.Should().Be(string.Empty); + options.Intents.Should().Be(0); + } + + [Fact] + public void Constructor_WhenCalledWithParameters_ItShouldCreateInstance() + { + var apiUrl = "https://api.example.com"; + var appToken = "test-token"; + var intents = 123; + + var options = new DiscordClientOptions + { + ApiUrl = apiUrl, + AppToken = appToken, + Intents = intents + }; + + options.Should().NotBeNull(); + options.Should().BeOfType(); + options.ApiUrl.Should().Be(apiUrl); + options.AppToken.Should().Be(appToken); + options.Intents.Should().Be(intents); + } +} \ No newline at end of file diff --git a/src/StevesBot.Worker.Tests/UnitTest1.cs b/src/StevesBot.Worker.Tests/UnitTest1.cs deleted file mode 100644 index f017831..0000000 --- a/src/StevesBot.Worker.Tests/UnitTest1.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace StevesBot.Worker.Tests; - -public class UnitTest1 -{ - [Fact] - public void Test1() - { - - } -} \ No newline at end of file diff --git a/src/StevesBot.Worker.Tests/Usings.cs b/src/StevesBot.Worker.Tests/Usings.cs new file mode 100644 index 0000000..a1cf763 --- /dev/null +++ b/src/StevesBot.Worker.Tests/Usings.cs @@ -0,0 +1 @@ +global using StevesBot.Worker.Discord; \ No newline at end of file diff --git a/src/StevesBot.Worker/.editorconfig b/src/StevesBot.Worker/.editorconfig new file mode 100644 index 0000000..2dc531e --- /dev/null +++ b/src/StevesBot.Worker/.editorconfig @@ -0,0 +1,2 @@ +[*.cs] +dotnet_diagnostic.CA2007.severity = none diff --git a/src/StevesBot.Worker/Discord/DiscordClientException.cs b/src/StevesBot.Worker/Discord/DiscordClientException.cs new file mode 100644 index 0000000..791cd04 --- /dev/null +++ b/src/StevesBot.Worker/Discord/DiscordClientException.cs @@ -0,0 +1,16 @@ +namespace StevesBot.Worker.Discord; + +internal class DiscordClientException : Exception +{ + public DiscordClientException() + { + } + + public DiscordClientException(string message) : base(message) + { + } + + public DiscordClientException(string message, Exception innerException) : base(message, innerException) + { + } +} \ No newline at end of file diff --git a/src/StevesBot.Worker/Discord/DiscordClientOptions.cs b/src/StevesBot.Worker/Discord/DiscordClientOptions.cs new file mode 100644 index 0000000..885d548 --- /dev/null +++ b/src/StevesBot.Worker/Discord/DiscordClientOptions.cs @@ -0,0 +1,8 @@ +namespace StevesBot.Worker.Discord; + +internal class DiscordClientOptions +{ + public string ApiUrl { get; init; } = string.Empty; + public string AppToken { get; init; } = string.Empty; + public int Intents { get; init; } +} diff --git a/src/StevesBot.Worker/Discord/Events/DiscordEvent.cs b/src/StevesBot.Worker/Discord/Events/DiscordEvent.cs new file mode 100644 index 0000000..7ac4ff8 --- /dev/null +++ b/src/StevesBot.Worker/Discord/Events/DiscordEvent.cs @@ -0,0 +1,16 @@ +namespace StevesBot.Worker.Discord.Events; + +internal record DiscordEvent +{ + [JsonPropertyName("op")] + public int Op { get; init; } + + [JsonPropertyName("s")] + public int? Sequence { get; init; } + + [JsonPropertyName("t")] + public string? Type { get; init; } + + [JsonPropertyName("d")] + public object? Data { get; init; } +} \ No newline at end of file diff --git a/src/StevesBot.Worker/Discord/Events/DiscordEventConverter.cs b/src/StevesBot.Worker/Discord/Events/DiscordEventConverter.cs new file mode 100644 index 0000000..8426030 --- /dev/null +++ b/src/StevesBot.Worker/Discord/Events/DiscordEventConverter.cs @@ -0,0 +1,24 @@ +namespace StevesBot.Worker.Discord.Events; + +internal class DiscordEventConverter : JsonConverter +{ + private const string OpPropertyName = "op"; + + public override DiscordEvent? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + using var jsonDoc = JsonDocument.ParseValue(ref reader); + var root = jsonDoc.RootElement; + var op = root.GetProperty(OpPropertyName).GetInt32(); + + return op switch + { + DiscordOpCodes.Hello => JsonSerializer.Deserialize(root.GetRawText(), options), + _ => JsonSerializer.Deserialize(root.GetRawText(), options) + }; + } + + public override void Write(Utf8JsonWriter writer, DiscordEvent value, JsonSerializerOptions options) + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/src/StevesBot.Worker/Discord/Events/DiscordOpCodes.cs b/src/StevesBot.Worker/Discord/Events/DiscordOpCodes.cs new file mode 100644 index 0000000..7eefb1d --- /dev/null +++ b/src/StevesBot.Worker/Discord/Events/DiscordOpCodes.cs @@ -0,0 +1,6 @@ +namespace StevesBot.Worker.Discord.Events; + +internal static class DiscordOpCodes +{ + public const int Hello = 10; +} \ No newline at end of file diff --git a/src/StevesBot.Worker/Discord/Events/HelloDiscordEvent.cs b/src/StevesBot.Worker/Discord/Events/HelloDiscordEvent.cs new file mode 100644 index 0000000..689442f --- /dev/null +++ b/src/StevesBot.Worker/Discord/Events/HelloDiscordEvent.cs @@ -0,0 +1,13 @@ +namespace StevesBot.Worker.Discord.Events; + +internal record HelloDiscordEvent : DiscordEvent +{ + [JsonPropertyName("d")] + public new HelloData? Data { get; init; } +} + +internal record HelloData +{ + [JsonPropertyName("heartbeat_interval")] + public int HeartbeatInterval { get; init; } +} diff --git a/src/StevesBot.Worker/Program.cs b/src/StevesBot.Worker/Program.cs index 0a8bb16..8e9cef5 100644 --- a/src/StevesBot.Worker/Program.cs +++ b/src/StevesBot.Worker/Program.cs @@ -4,4 +4,4 @@ var builder = Host.CreateApplicationBuilder(args); builder.Services.AddHostedService(); var host = builder.Build(); -host.Run(); \ No newline at end of file +await host.RunAsync(); \ No newline at end of file diff --git a/src/StevesBot.Worker/StevesBot.Worker.csproj b/src/StevesBot.Worker/StevesBot.Worker.csproj index 14e07c3..1bb4602 100644 --- a/src/StevesBot.Worker/StevesBot.Worker.csproj +++ b/src/StevesBot.Worker/StevesBot.Worker.csproj @@ -1,13 +1,15 @@ - net9.0 - enable - enable dotnet-StevesBot.Worker-0b7a94ae-5cbd-406d-8422-1c791715ef7d + + + + + diff --git a/src/StevesBot.Worker/Usings.cs b/src/StevesBot.Worker/Usings.cs new file mode 100644 index 0000000..a344eb9 --- /dev/null +++ b/src/StevesBot.Worker/Usings.cs @@ -0,0 +1,2 @@ +global using System.Text.Json; +global using System.Text.Json.Serialization; \ No newline at end of file diff --git a/src/StevesBot.Worker/Worker.cs b/src/StevesBot.Worker/Worker.cs index 19cef50..610b3a1 100644 --- a/src/StevesBot.Worker/Worker.cs +++ b/src/StevesBot.Worker/Worker.cs @@ -1,6 +1,6 @@ namespace StevesBot.Worker; -public class Worker : BackgroundService +internal class Worker : BackgroundService { private readonly ILogger _logger; @@ -15,8 +15,9 @@ public class Worker : BackgroundService { if (_logger.IsEnabled(LogLevel.Information)) { - _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now); + _logger.LogInformation("Worker running at: {Time}", DateTimeOffset.Now); } + await Task.Delay(1000, stoppingToken); } } diff --git a/src/StevesBot.Worker/appsettings.Example.json b/src/StevesBot.Worker/appsettings.Example.json new file mode 100644 index 0000000..db47611 --- /dev/null +++ b/src/StevesBot.Worker/appsettings.Example.json @@ -0,0 +1,13 @@ +{ + "Logging": { + "LogLevel": { + "Default": "Information", + "Microsoft.Hosting.Lifetime": "Information" + } + }, + "DiscordClientOptions": { + "ApiUrl": "ApiUrl", + "AppToken": "AppToken", + "Intents": 0 + } +}