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(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, RedisOptions.Key})).Bind(options.RedisOptions);
}
public static RootOptions ConfigureOptions(IConfiguration config)
@ -35,6 +36,7 @@ namespace Selector.CLI
public string ClientSecret { get; set; }
public WatcherOptions WatcherOptions { get; set; } = new();
public DatabaseOptions DatabaseOptions { get; set; } = new();
public RedisOptions RedisOptions { get; set; } = new();
public EqualityChecker Equality { get; set; } = EqualityChecker.Uri;
}
@ -78,4 +80,12 @@ namespace Selector.CLI
public bool Enabled { get; set; } = false;
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 Selector.Model;
using Selector.Cache;
using StackExchange.Redis;
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)
{
case EqualityChecker.Uri:

View File

@ -12,7 +12,7 @@
<PackageReference Include="Microsoft.Extensions.Hosting" 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="NLog" Version="4.7.11" />
<PackageReference Include="NLog" Version="4.7.12" />
<PackageReference Include="NLog.Extensions.Logging" Version="1.7.4" />
<PackageReference Include="SpotifyAPI.Web" Version="6.2.2" />
</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">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
<TargetFramework>net5.0</TargetFramework>
<EnableDefaultCompileItems>true</EnableDefaultCompileItems>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<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>
</Project>

View File

@ -8,7 +8,7 @@
</PropertyGroup>
<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="Moq" Version="4.16.1" />
<PackageReference Include="xunit" Version="2.4.1" />

View File

@ -3,11 +3,12 @@ using Microsoft.Extensions.Configuration;
namespace Selector.Web
{
public static class OptionsHelper {
static class OptionsHelper {
public static void ConfigureOptions(RootOptions options, IConfiguration config)
{
config.GetSection(RootOptions.Key).Bind(options);
}
config.GetSection(FormatKeys(new[] { RootOptions.Key, RedisOptions.Key })).Bind(options.RedisOptions);
}
public static RootOptions ConfigureOptions(IConfiguration config)
{
@ -35,5 +36,16 @@ namespace Selector.Web
/// Spotify callback for authentication
/// </summary>
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>
</PackageReference>
<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.Web.AspNetCore" Version="4.14.0" />
</ItemGroup>

View File

@ -13,8 +13,11 @@ using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.EntityFrameworkCore;
using StackExchange.Redis;
using Selector.Model;
using Selector.Model.Authorisation;
using Selector.Cache;
namespace Selector.Web
{
@ -34,6 +37,7 @@ namespace Selector.Web
{
OptionsHelper.ConfigureOptions(options, Configuration);
});
var config = OptionsHelper.ConfigureOptions(Configuration);
services.AddRazorPages().AddRazorRuntimeCompilation();
services.AddControllers();
@ -92,6 +96,23 @@ namespace Selector.Web
services.AddScoped<IAuthorizationHandler, UserIsSelfAuthHandler>();
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.