Skip to content

Commit

Permalink
feat: initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
cptchloroplast committed Jan 6, 2024
0 parents commit 52a3876
Show file tree
Hide file tree
Showing 43 changed files with 1,007 additions and 0 deletions.
32 changes: 32 additions & 0 deletions .github/workflows/nuget.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: nuget
on:
push:
paths:
- src/**
- test/**
- Okkema.sln
- .github/workflows/nuget.yaml
concurrency: nuget
jobs:
nuget:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Setup dotnet
uses: actions/setup-dotnet@v3
with:
dotnet-version: 6.x
source-url: https://nuget.pkg.github.com/okkema/index.json
env:
NUGET_AUTH_TOKEN: ${{secrets.GITHUB_TOKEN}}
- name: Build solution
run: dotnet build
- name: Test solution
run: dotnet test
- name: Package release
run: dotnet pack --configuration Release
- name: Publish release
run: dotnet nuget push src/**/bin/Release/*.nupkg --skip-duplicate


2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bin
obj
78 changes: 78 additions & 0 deletions Okkema.sln
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.0.31903.59
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{63284BC1-0B65-4978-96E0-8FC776A25137}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Okkema.Cache", "src\Okkema.Cache\Okkema.Cache.csproj", "{7032D94B-6467-4EB7-A44D-5B0970B3A0AE}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Okkema.Messages", "src\Okkema.Messages\Okkema.Messages.csproj", "{9B1317F2-E6D2-4AD0-930A-C6F8E31BFE50}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Okkema.Queue", "src\Okkema.Queue\Okkema.Queue.csproj", "{6F026E63-5067-4212-A246-14CC936F2747}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Okkema.SQL", "src\Okkema.SQL\Okkema.SQL.csproj", "{8A76B4D7-4ACE-4A63-84B8-3FF3E0BD42EC}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{4F3AF5ED-CBA8-4D32-B754-60B246F885FD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Okkema.Cache.Test", "test\Okkema.Cache.Test\Okkema.Cache.Test.csproj", "{D1FE27D3-D7AC-4FC0-AFEC-18E52ACB5EA1}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Okkema.Queue.Test", "test\Okkema.Queue.Test\Okkema.Queue.Test.csproj", "{B68169EE-B6C2-4F30-9CBA-95958480630C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Okkema.SQL.Test", "test\Okkema.SQL.Test\Okkema.SQL.Test.csproj", "{147200B7-C2D3-4745-9223-38D8ABB2C4C8}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Okkema.Test", "test\Okkema.Test\Okkema.Test.csproj", "{3A584C1A-D18A-44DB-B6EC-FDB66CDB7D04}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{7032D94B-6467-4EB7-A44D-5B0970B3A0AE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7032D94B-6467-4EB7-A44D-5B0970B3A0AE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7032D94B-6467-4EB7-A44D-5B0970B3A0AE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7032D94B-6467-4EB7-A44D-5B0970B3A0AE}.Release|Any CPU.Build.0 = Release|Any CPU
{9B1317F2-E6D2-4AD0-930A-C6F8E31BFE50}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9B1317F2-E6D2-4AD0-930A-C6F8E31BFE50}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9B1317F2-E6D2-4AD0-930A-C6F8E31BFE50}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9B1317F2-E6D2-4AD0-930A-C6F8E31BFE50}.Release|Any CPU.Build.0 = Release|Any CPU
{6F026E63-5067-4212-A246-14CC936F2747}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6F026E63-5067-4212-A246-14CC936F2747}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6F026E63-5067-4212-A246-14CC936F2747}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6F026E63-5067-4212-A246-14CC936F2747}.Release|Any CPU.Build.0 = Release|Any CPU
{8A76B4D7-4ACE-4A63-84B8-3FF3E0BD42EC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8A76B4D7-4ACE-4A63-84B8-3FF3E0BD42EC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8A76B4D7-4ACE-4A63-84B8-3FF3E0BD42EC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8A76B4D7-4ACE-4A63-84B8-3FF3E0BD42EC}.Release|Any CPU.Build.0 = Release|Any CPU
{D1FE27D3-D7AC-4FC0-AFEC-18E52ACB5EA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D1FE27D3-D7AC-4FC0-AFEC-18E52ACB5EA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D1FE27D3-D7AC-4FC0-AFEC-18E52ACB5EA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D1FE27D3-D7AC-4FC0-AFEC-18E52ACB5EA1}.Release|Any CPU.Build.0 = Release|Any CPU
{B68169EE-B6C2-4F30-9CBA-95958480630C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B68169EE-B6C2-4F30-9CBA-95958480630C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B68169EE-B6C2-4F30-9CBA-95958480630C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B68169EE-B6C2-4F30-9CBA-95958480630C}.Release|Any CPU.Build.0 = Release|Any CPU
{147200B7-C2D3-4745-9223-38D8ABB2C4C8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{147200B7-C2D3-4745-9223-38D8ABB2C4C8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{147200B7-C2D3-4745-9223-38D8ABB2C4C8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{147200B7-C2D3-4745-9223-38D8ABB2C4C8}.Release|Any CPU.Build.0 = Release|Any CPU
{3A584C1A-D18A-44DB-B6EC-FDB66CDB7D04}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3A584C1A-D18A-44DB-B6EC-FDB66CDB7D04}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3A584C1A-D18A-44DB-B6EC-FDB66CDB7D04}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3A584C1A-D18A-44DB-B6EC-FDB66CDB7D04}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{7032D94B-6467-4EB7-A44D-5B0970B3A0AE} = {63284BC1-0B65-4978-96E0-8FC776A25137}
{9B1317F2-E6D2-4AD0-930A-C6F8E31BFE50} = {63284BC1-0B65-4978-96E0-8FC776A25137}
{6F026E63-5067-4212-A246-14CC936F2747} = {63284BC1-0B65-4978-96E0-8FC776A25137}
{8A76B4D7-4ACE-4A63-84B8-3FF3E0BD42EC} = {63284BC1-0B65-4978-96E0-8FC776A25137}
{D1FE27D3-D7AC-4FC0-AFEC-18E52ACB5EA1} = {4F3AF5ED-CBA8-4D32-B754-60B246F885FD}
{B68169EE-B6C2-4F30-9CBA-95958480630C} = {4F3AF5ED-CBA8-4D32-B754-60B246F885FD}
{147200B7-C2D3-4745-9223-38D8ABB2C4C8} = {4F3AF5ED-CBA8-4D32-B754-60B246F885FD}
{3A584C1A-D18A-44DB-B6EC-FDB66CDB7D04} = {4F3AF5ED-CBA8-4D32-B754-60B246F885FD}
EndGlobalSection
EndGlobal
42 changes: 42 additions & 0 deletions src/Okkema.Cache/CacheService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
using Microsoft.Extensions.Caching.Distributed;
using System.Text.Json;
namespace Okkema.Cache;
public sealed class CacheService<T> : ICacheService<T> where T : class, new()
{
private readonly IDistributedCache _cache;
private readonly CacheSignal<T> _signal;
public CacheService(IDistributedCache cache,
CacheSignal<T> signal)
{
_cache = cache ?? throw new ArgumentNullException(nameof(cache));
_signal = signal ?? throw new ArgumentNullException(nameof(signal));

}
public async Task<T?> GetAsync(string key, CancellationToken token = default)
{
try
{
await _signal.WaitAsync();
var json = await _cache.GetStringAsync(key, token);
if (string.IsNullOrWhiteSpace(json)) return default;
return JsonSerializer.Deserialize<T>(json);
}
finally
{
_signal.Release();
}
}
public async Task SetAsync(string key, T value, CancellationToken token = default)
{
try
{
await _signal.WaitAsync();
var json = JsonSerializer.Serialize(value);
await _cache.SetStringAsync(key, json, token);
}
finally
{
_signal.Release();
}
}
}
7 changes: 7 additions & 0 deletions src/Okkema.Cache/CacheSignal.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Okkema.Cache;
public sealed class CacheSignal<T>
{
private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
public Task WaitAsync() => _semaphore.WaitAsync();
public void Release() => _semaphore.Release();
}
17 changes: 17 additions & 0 deletions src/Okkema.Cache/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
namespace Okkema.Cache.Extensions;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMemoryCache(this IServiceCollection services, IConfiguration configuration)
{
services.AddDistributedMemoryCache();
return services;
}
public static IServiceCollection AddCacheService<T>(this IServiceCollection services, IConfiguration configuration) where T : class, new()
{
services.AddSingleton<CacheSignal<T>>();
services.AddScoped<ICacheService<T>, CacheService<T>>();
return services;
}
}
6 changes: 6 additions & 0 deletions src/Okkema.Cache/ICacheService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Okkema.Cache;
public interface ICacheService<T>
{
public Task<T?> GetAsync(string key, CancellationToken token);
public Task SetAsync(string key, T value, CancellationToken token);
}
21 changes: 21 additions & 0 deletions src/Okkema.Cache/Okkema.Cache.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PackageId>Okkema.Cache</PackageId>
<Version>0.1.0</Version>
<Authors>Benjamin Okkema</Authors>
<Company>Okkema Labs</Company>
<PackageDescription>Okkema Labs Cache Utilities</PackageDescription>
<RepositoryUrl>https://github.com/cptchloroplast/movies</RepositoryUrl>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Caching.Memory" Version="8.*" />
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.*" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.*" />
</ItemGroup>

</Project>
18 changes: 18 additions & 0 deletions src/Okkema.Messages/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Configuration;
using Okkema.Queue.Extensions;
using Okkema.Messages;
using Okkema.Messages.Handlers;
namespace Okkema.Messages.Extensions;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddMessageHandler<TMessage, THandler>(this IServiceCollection services)
where TMessage : MessageBase
where THandler : MessageHandlerBase<TMessage>
{
services.AddHostedService<THandler>();
services.AddSingleton<IMessageHandler<TMessage>, THandler>();
services.AddChannelConsumer<TMessage>();
return services;
}
}
5 changes: 5 additions & 0 deletions src/Okkema.Messages/Handlers/IMessageHandler.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Okkema.Messages.Handlers;
public interface IMessageHandler<T> where T : MessageBase
{
public Task HandleAsync(T message, CancellationToken cancellationToken = default);
}
26 changes: 26 additions & 0 deletions src/Okkema.Messages/Handlers/MessageHandlerBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Hosting;
using Okkema.Queue.Consumers;
namespace Okkema.Messages.Handlers;
public abstract class MessageHandlerBase<T> : BackgroundService, IMessageHandler<T>
where T : MessageBase
{
protected readonly ILogger<MessageHandlerBase<T>> _logger;
private readonly IConsumer<T> _consumer;
public MessageHandlerBase(
ILogger<MessageHandlerBase<T>> logger,
IConsumer<T> consumer)
{
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
_consumer = consumer ?? throw new ArgumentNullException(nameof(consumer));
}
protected override async Task ExecuteAsync(CancellationToken cancellationToken)
{
while (!cancellationToken.IsCancellationRequested)
{
await _consumer.ReadAsync(HandleAsync, cancellationToken);
}
}
public abstract Task HandleAsync(T message, CancellationToken cancellationToken = default);

}
6 changes: 6 additions & 0 deletions src/Okkema.Messages/MessageBase.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
namespace Okkema.Messages;
public abstract record MessageBase
{
public Guid SystemKey { get; init; } = Guid.NewGuid();
public DateTime SystemCreatedDate { get; init; } = DateTime.UtcNow;
}
25 changes: 25 additions & 0 deletions src/Okkema.Messages/Okkema.Messages.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PackageId>Okkema.Messages</PackageId>
<Version>0.1.1</Version>
<Authors>Benjamin Okkema</Authors>
<Company>Okkema Labs</Company>
<PackageDescription>Okkema Labs Message Utilities</PackageDescription>
<RepositoryUrl>https://github.com/okkema/dotnet</RepositoryUrl>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\Okkema.Queue\Okkema.Queue.csproj" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.*" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.*" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="8.*" />
</ItemGroup>

</Project>
22 changes: 22 additions & 0 deletions src/Okkema.Queue/Consumers/ChannelConsmer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.Threading.Channels;
namespace Okkema.Queue.Consumers;
public sealed class ChannelConsumer<T> : IConsumer<T>
{
private readonly Channel<T> _channel;
public ChannelConsumer(
Channel<T> channel)
{
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
}
public async Task ReadAsync(Func<T, CancellationToken, Task> callback, CancellationToken cancellationToken = default)
{
while (!cancellationToken.IsCancellationRequested
&& await _channel.Reader.WaitToReadAsync())
{
if (_channel.Reader.TryRead(out var value))
{
await callback(value, cancellationToken);
}
}
}
}
5 changes: 5 additions & 0 deletions src/Okkema.Queue/Consumers/IConsumer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
namespace Okkema.Queue.Consumers;
public interface IConsumer<T>
{
public Task ReadAsync(Func<T, CancellationToken, Task> callback, CancellationToken cancellationToken = default);
}
23 changes: 23 additions & 0 deletions src/Okkema.Queue/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Okkema.Queue.Consumers;
using Okkema.Queue.Producers;
using System.Threading.Channels;
namespace Okkema.Queue.Extensions;
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddChannelConsumer<T>(this IServiceCollection services)
where T : class
{
services.AddSingleton<IConsumer<T>, ChannelConsumer<T>>();
services.TryAddSingleton(Channel.CreateUnbounded<T>());
return services;
}
public static IServiceCollection AddChannelProducer<T>(this IServiceCollection services)
where T : class
{
services.AddSingleton<IProducer<T>, ChannelProducer<T>>();
services.TryAddSingleton(Channel.CreateUnbounded<T>());
return services;
}
}
21 changes: 21 additions & 0 deletions src/Okkema.Queue/Okkema.Queue.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<PackageId>Okkema.Queue</PackageId>
<Version>0.1.0</Version>
<Authors>Benjamin Okkema</Authors>
<Company>Okkema Labs</Company>
<PackageDescription>Okkema Labs Queue Utilities</PackageDescription>
<RepositoryUrl>https://github.com/okkema/dotnet</RepositoryUrl>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="System.Threading.Channels" Version="8.*" />
<PackageReference Include="System.Threading.Tasks.Extensions" Version="4.*" />
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="8.*" />
</ItemGroup>

</Project>
15 changes: 15 additions & 0 deletions src/Okkema.Queue/Producers/ChannelProducer.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
using System.Threading.Channels;
namespace Okkema.Queue.Producers;
public sealed class ChannelProducer<T> : IProducer<T>
{
private readonly Channel<T> _channel;
public ChannelProducer(
Channel<T> channel)
{
_channel = channel ?? throw new ArgumentNullException(nameof(channel));
}
public async Task WriteAsync(T value)
{
await _channel.Writer.WriteAsync(value);
}
}
Loading

0 comments on commit 52a3876

Please sign in to comment.