Skip to content

Commit

Permalink
Add MiniTwitch.PubSub (#25)
Browse files Browse the repository at this point in the history
  • Loading branch information
occluder authored Sep 23, 2023
1 parent 371c6bf commit 22de677
Show file tree
Hide file tree
Showing 76 changed files with 6,651 additions and 10 deletions.
5 changes: 4 additions & 1 deletion MiniTwitch.Common/AsyncEventCoordinator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,15 @@ public async Task<TEnum> WaitForAny(IEnumerable<TEnum> values, TimeSpan timeout,
{
TEnum[] valuesArr = values.ToArray();
var tasks = new Task<bool>[valuesArr.Length];
CancellationToken token = new(false);
CancellationTokenSource tokenSource = CancellationTokenSource.CreateLinkedTokenSource(token, cancellationToken);
for (int i = 0; i < valuesArr.Length; i++)
{
tasks[i] = WaitFor(valuesArr[i], timeout, cancellationToken);
tasks[i] = WaitFor(valuesArr[i], timeout, tokenSource.Token);
}

_ = await Task.WhenAny(tasks);
tokenSource.Cancel();
for (int i = 0; i < tasks.Length; i++)
{
if (tasks[i].IsCompleted && tasks[i].Result == true)
Expand Down
52 changes: 52 additions & 0 deletions MiniTwitch.Common/DefaultMiniTwitchLogger.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
using Microsoft.Extensions.Logging;

namespace MiniTwitch.Common;

public class DefaultMiniTwitchLogger<T> : ILogger<T>, ILogger
{
public bool Enabled { get; set; } = true;
public LogLevel MinimumLevel { get; set; } = LogLevel.Information;

private static readonly object _lock = new();

public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception? exception, Func<TState, Exception?, string> formatter)
{
if (!IsEnabled(logLevel))
return;

lock (_lock)
{
Console.Write($"[{DateTimeOffset.Now:HH:mm:ss} ");
Console.ForegroundColor = logLevel switch
{
LogLevel.Trace => ConsoleColor.Gray,
LogLevel.Debug => ConsoleColor.DarkMagenta,
LogLevel.Information => ConsoleColor.DarkCyan,
LogLevel.Warning => ConsoleColor.Yellow,
LogLevel.Critical => ConsoleColor.DarkYellow,
_ => ConsoleColor.Red
};

Console.Write(logLevel switch
{
LogLevel.Trace => "Trace",
LogLevel.Debug => "Debug",
LogLevel.Information => "Information",
LogLevel.Warning => "Warning",
LogLevel.Error => "Error",
LogLevel.Critical => "Critical",
LogLevel.None => "None",
_ => "[?????] "
});

Console.ResetColor();
Console.Write("] ");
string message = formatter(state, exception);
Console.WriteLine(message);
if (exception is not null)
Console.WriteLine(exception);
}
}
public bool IsEnabled(LogLevel logLevel) => this.Enabled && logLevel >= this.MinimumLevel;
public IDisposable? BeginScope<TState>(TState state) where TState : notnull => throw new NotImplementedException();
}
57 changes: 57 additions & 0 deletions MiniTwitch.PubSub.Test/DeserializationTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using System.Reflection;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using MiniTwitch.PubSub.Internal.Parsing;

namespace MiniTwitch.PubSub.Test;

// The sole purpose of these tests is to make sure that deserialization doesn't throw exceptions
public class DeserializationTests
{
private static readonly JsonSerializerOptions _sOptions = new()
{
NumberHandling = JsonNumberHandling.AllowReadingFromString,
DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingDefault,
ReadCommentHandling = JsonCommentHandling.Skip
};

[Fact]
public void DeserializePayloads()
{
foreach (var field in typeof(Payloads).GetFields(BindingFlags.NonPublic | BindingFlags.Static))
{
TopicAttribute attribute = (TopicAttribute)Attribute.GetCustomAttribute(field, typeof(TopicAttribute))!;
try
{
Assert.NotNull(JsonSerializer.Deserialize(field.GetValue(null)?.ToString()!, attribute.OutType, _sOptions));
}
catch (Exception ex)
{
Assert.Fail($"[field: {field.Name}] Deserialization to {attribute.OutType.Name} failure! {ex.Message}\n{ex.StackTrace}");
}
}
}

[Fact]
public void DeserializePayloads_ReadJsonMessage()
{
foreach (var field in typeof(Payloads).GetFields(BindingFlags.NonPublic | BindingFlags.Static))
{
TopicAttribute attribute = (TopicAttribute)Attribute.GetCustomAttribute(field, typeof(TopicAttribute))!;
try
{
object? des = PubSubParsing.ReadJsonMessage(Encoding.UTF8.GetBytes(attribute.GetJsonMessage(field)), attribute.OutType, options: _sOptions);
Assert.NotNull(des);
if (des is string str)
{
Assert.Fail(str);
}
}
catch (Exception ex)
{
Assert.Fail($"[field: {field.Name}] Deserialization to {attribute.OutType.Name} failure! {ex.Message}\n{ex.StackTrace}");
}
}
}
}
1 change: 1 addition & 0 deletions MiniTwitch.PubSub.Test/GlobalUsings.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
global using Xunit;
29 changes: 29 additions & 0 deletions MiniTwitch.PubSub.Test/MiniTwitch.PubSub.Test.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net7.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>

<IsPackable>false</IsPackable>
<IsTestProject>true</IsTestProject>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.6.0" />
<PackageReference Include="xunit" Version="2.4.2" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.5">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="coverlet.collector" Version="3.2.0">
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\MiniTwitch.PubSub\MiniTwitch.PubSub.csproj" />
</ItemGroup>

</Project>
Loading

0 comments on commit 22de677

Please sign in to comment.