adding cache, ICache. RedisOptions and registering services in CLI and web app

This commit is contained in:
andy 2021-10-27 23:00:01 +01:00
parent 222c738854
commit 1714e3f911
13 changed files with 168 additions and 6 deletions

View File

@ -9,6 +9,7 @@ namespace Selector.CLI
config.GetSection(RootOptions.Key).Bind(options); config.GetSection(RootOptions.Key).Bind(options);
config.GetSection(FormatKeys( new[] { RootOptions.Key, WatcherOptions.Key})).Bind(options.WatcherOptions); config.GetSection(FormatKeys( new[] { RootOptions.Key, WatcherOptions.Key})).Bind(options.WatcherOptions);
config.GetSection(FormatKeys( new[] { RootOptions.Key, DatabaseOptions.Key})).Bind(options.DatabaseOptions); config.GetSection(FormatKeys( new[] { RootOptions.Key, DatabaseOptions.Key})).Bind(options.DatabaseOptions);
config.GetSection(FormatKeys( new[] { RootOptions.Key, RedisOptions.Key})).Bind(options.RedisOptions);
} }
public static RootOptions ConfigureOptions(IConfiguration config) public static RootOptions ConfigureOptions(IConfiguration config)
@ -35,6 +36,7 @@ namespace Selector.CLI
public string ClientSecret { get; set; } public string ClientSecret { get; set; }
public WatcherOptions WatcherOptions { get; set; } = new(); public WatcherOptions WatcherOptions { get; set; } = new();
public DatabaseOptions DatabaseOptions { get; set; } = new(); public DatabaseOptions DatabaseOptions { get; set; } = new();
public RedisOptions RedisOptions { get; set; } = new();
public EqualityChecker Equality { get; set; } = EqualityChecker.Uri; public EqualityChecker Equality { get; set; } = EqualityChecker.Uri;
} }
@ -78,4 +80,12 @@ namespace Selector.CLI
public bool Enabled { get; set; } = false; public bool Enabled { get; set; } = false;
public string ConnectionString { get; set; } public string ConnectionString { get; set; }
} }
class RedisOptions
{
public const string Key = "Redis";
public bool Enabled { get; set; } = false;
public string ConnectionString { get; set; }
}
} }

View File

@ -8,6 +8,8 @@ using Microsoft.EntityFrameworkCore;
using NLog.Extensions.Logging; using NLog.Extensions.Logging;
using Selector.Model; using Selector.Model;
using Selector.Cache;
using StackExchange.Redis;
namespace Selector.CLI namespace Selector.CLI
{ {
@ -51,6 +53,23 @@ namespace Selector.CLI
); );
} }
if (config.RedisOptions.Enabled)
{
Console.WriteLine("> Configuring Redis...");
if(string.IsNullOrWhiteSpace(config.RedisOptions.ConnectionString))
{
Console.WriteLine("> No Redis configuration string provided, exiting...");
Environment.Exit(1);
}
var connMulti = ConnectionMultiplexer.Connect(config.RedisOptions.ConnectionString);
services.AddSingleton(connMulti);
services.AddSingleton<IDatabaseAsync>(connMulti.GetDatabase());
services.AddSingleton<ICache<string>, RedisCache>();
}
switch (config.Equality) switch (config.Equality)
{ {
case EqualityChecker.Uri: case EqualityChecker.Uri:

View File

@ -12,7 +12,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Hosting" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" /> <PackageReference Include="Microsoft.Extensions.Logging.Console" Version="5.0.0" />
<PackageReference Include="NLog" Version="4.7.11" /> <PackageReference Include="NLog" Version="4.7.12" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" /> <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
<PackageReference Include="SpotifyAPI.Web" Version="6.2.2" /> <PackageReference Include="SpotifyAPI.Web" Version="6.2.2" />
</ItemGroup> </ItemGroup>

24
Selector.Cache/ICache.cs Normal file
View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Selector.Cache
{
public interface ICache<TKey>
{
public Task<string> Get(TKey key);
public Task<bool> Set(TKey key, string value);
}
/// <summary>
/// Is this unnecessary?
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TKey"></typeparam>
public interface ICacheSerialiser<T, TKey>
{
public Task<bool> Write(TKey key, T obj, ICache<TKey> cache);
public Task<T> Read(TKey key, ICache<TKey> cache);
}
}

View File

@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.Json;
using System.Threading.Tasks;
using SpotifyAPI.Web;
namespace Selector.Cache
{
public static class JsonSerialiser
{
public static async Task<T> Read<T>(this ICache<string> cache, string key)
=> JsonSerializer.Deserialize<T>(await cache.Get(key));
public static async Task<bool> Write<T>(this ICache<string> cache, string key, T obj)
=> await cache.Set(key, JsonSerializer.Serialize(obj));
}
}

15
Selector.Cache/Key.cs Normal file
View File

@ -0,0 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Selector.Cache
{
public class Key
{
public const string CurrentlyPlayingName = "CurrentlyPlaying";
public static string CurrentlyPlaying(string user) => Namespace(new[] { user, CurrentlyPlayingName });
public static string Namespace(string[] args) => string.Join(":", args);
}
}

11
Selector.Cache/Model.cs Normal file
View File

@ -0,0 +1,11 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace Selector.Cache
{
public class CurrentPlaying
{
}
}

View File

@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using StackExchange.Redis;
namespace Selector.Cache
{
public class RedisCache : ICache<string>
{
private readonly IDatabaseAsync Db;
public RedisCache(
IDatabaseAsync db
) {
Db = db;
}
public async Task<string> Get(string key) => (await Db.StringGetAsync(key)).ToString();
public async Task<bool> Set(string key, string value) => await Db.StringSetAsync(key, value);
}
}

View File

@ -1,13 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework> <TargetFramework>net5.0</TargetFramework>
<EnableDefaultCompileItems>true</EnableDefaultCompileItems> <EnableDefaultCompileItems>true</EnableDefaultCompileItems>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="StackExchange.Redis" Version="2.2.79" /> <PackageReference Include="StackExchange.Redis" Version="2.2.79" />
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
<PackageReference Include="SpotifyAPI.Web" Version="6.2.2" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Selector\Selector.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>

View File

@ -8,7 +8,7 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="FluentAssertions" Version="6.1.0" /> <PackageReference Include="FluentAssertions" Version="6.2.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" /> <PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.1" />
<PackageReference Include="Moq" Version="4.16.1" /> <PackageReference Include="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" /> <PackageReference Include="xunit" Version="2.4.1" />

View File

@ -3,10 +3,11 @@ using Microsoft.Extensions.Configuration;
namespace Selector.Web namespace Selector.Web
{ {
public static class OptionsHelper { static class OptionsHelper {
public static void ConfigureOptions(RootOptions options, IConfiguration config) public static void ConfigureOptions(RootOptions options, IConfiguration config)
{ {
config.GetSection(RootOptions.Key).Bind(options); config.GetSection(RootOptions.Key).Bind(options);
config.GetSection(FormatKeys(new[] { RootOptions.Key, RedisOptions.Key })).Bind(options.RedisOptions);
} }
public static RootOptions ConfigureOptions(IConfiguration config) public static RootOptions ConfigureOptions(IConfiguration config)
@ -35,5 +36,16 @@ namespace Selector.Web
/// Spotify callback for authentication /// Spotify callback for authentication
/// </summary> /// </summary>
public string SpotifyCallback { get; set; } public string SpotifyCallback { get; set; }
public RedisOptions RedisOptions { get; set; } = new();
}
public class RedisOptions
{
public const string Key = "Redis";
public bool Enabled { get; set; } = false;
public string ConnectionString { get; set; }
} }
} }

View File

@ -27,7 +27,7 @@
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
<PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" /> <PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="5.0.2" />
<PackageReference Include="NLog" Version="4.7.11" /> <PackageReference Include="NLog" Version="4.7.12" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" /> <PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
<PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0" /> <PackageReference Include="NLog.Web.AspNetCore" Version="4.14.0" />
</ItemGroup> </ItemGroup>

View File

@ -13,8 +13,11 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;
using Selector.Model; using Selector.Model;
using Selector.Model.Authorisation; using Selector.Model.Authorisation;
using Selector.Cache;
namespace Selector.Web namespace Selector.Web
{ {
@ -34,6 +37,7 @@ namespace Selector.Web
{ {
OptionsHelper.ConfigureOptions(options, Configuration); OptionsHelper.ConfigureOptions(options, Configuration);
}); });
var config = OptionsHelper.ConfigureOptions(Configuration);
services.AddRazorPages().AddRazorRuntimeCompilation(); services.AddRazorPages().AddRazorRuntimeCompilation();
services.AddControllers(); services.AddControllers();
@ -92,6 +96,23 @@ namespace Selector.Web
services.AddScoped<IAuthorizationHandler, UserIsSelfAuthHandler>(); services.AddScoped<IAuthorizationHandler, UserIsSelfAuthHandler>();
services.AddSingleton<IAuthorizationHandler, UserIsAdminAuthHandler>(); services.AddSingleton<IAuthorizationHandler, UserIsAdminAuthHandler>();
if (config.RedisOptions.Enabled)
{
Console.WriteLine("> Configuring Redis...");
if (string.IsNullOrWhiteSpace(config.RedisOptions.ConnectionString))
{
Console.WriteLine("> No Redis configuration string provided, exiting...");
Environment.Exit(1);
}
var connMulti = ConnectionMultiplexer.Connect(config.RedisOptions.ConnectionString);
services.AddSingleton(connMulti);
services.AddSingleton<IDatabaseAsync>(connMulti.GetDatabase());
services.AddSingleton<ICache<string>, RedisCache>();
}
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.