more DI for consumer factories, caching play counter, service extensions
This commit is contained in:
parent
975ee772dd
commit
e41d525b0b
@ -25,38 +25,45 @@ namespace Selector.CLI
|
||||
private readonly ILogger<LocalWatcherService> Logger;
|
||||
private readonly ILoggerFactory LoggerFactory;
|
||||
private readonly IServiceProvider ServiceProvider;
|
||||
private readonly RootOptions Config;
|
||||
|
||||
private readonly IWatcherFactory WatcherFactory;
|
||||
private readonly IWatcherCollectionFactory WatcherCollectionFactory;
|
||||
private readonly IRefreshTokenFactoryProvider SpotifyFactory;
|
||||
private readonly LastAuth LastAuth;
|
||||
|
||||
private readonly IDatabaseAsync Cache;
|
||||
private readonly ISubscriber Subscriber;
|
||||
private readonly IAudioFeatureInjectorFactory AudioFeatureInjectorFactory;
|
||||
private readonly IPlayCounterFactory PlayCounterFactory;
|
||||
|
||||
private readonly IPublisherFactory PublisherFactory;
|
||||
private readonly ICacheWriterFactory CacheWriterFactory;
|
||||
private Dictionary<string, IWatcherCollection> Watchers { get; set; } = new();
|
||||
|
||||
public DbWatcherService(
|
||||
IWatcherFactory watcherFactory,
|
||||
IWatcherCollectionFactory watcherCollectionFactory,
|
||||
IRefreshTokenFactoryProvider spotifyFactory,
|
||||
|
||||
IAudioFeatureInjectorFactory audioFeatureInjectorFactory,
|
||||
IPlayCounterFactory playCounterFactory,
|
||||
|
||||
IPublisherFactory publisherFactory,
|
||||
ICacheWriterFactory cacheWriterFactory,
|
||||
|
||||
ILoggerFactory loggerFactory,
|
||||
IServiceProvider serviceProvider,
|
||||
IOptions<RootOptions> config,
|
||||
LastAuth lastAuth = null,
|
||||
IDatabaseAsync cache = null,
|
||||
ISubscriber subscriber = null
|
||||
IServiceProvider serviceProvider
|
||||
) {
|
||||
Logger = loggerFactory.CreateLogger<LocalWatcherService>();
|
||||
LoggerFactory = loggerFactory;
|
||||
Config = config.Value;
|
||||
ServiceProvider = serviceProvider;
|
||||
|
||||
WatcherFactory = watcherFactory;
|
||||
WatcherCollectionFactory = watcherCollectionFactory;
|
||||
SpotifyFactory = spotifyFactory;
|
||||
LastAuth = lastAuth;
|
||||
ServiceProvider = serviceProvider;
|
||||
Cache = cache;
|
||||
Subscriber = subscriber;
|
||||
|
||||
AudioFeatureInjectorFactory = audioFeatureInjectorFactory;
|
||||
PlayCounterFactory = playCounterFactory;
|
||||
|
||||
PublisherFactory = publisherFactory;
|
||||
CacheWriterFactory = cacheWriterFactory;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
@ -99,26 +106,13 @@ namespace Selector.CLI
|
||||
case WatcherType.Player:
|
||||
watcher = await WatcherFactory.Get<PlayerWatcher>(spotifyFactory, id: dbWatcher.UserId, pollPeriod: PollPeriod);
|
||||
|
||||
var featureInjector = new AudioFeatureInjectorFactory(LoggerFactory);
|
||||
consumers.Add(await featureInjector.Get(spotifyFactory));
|
||||
|
||||
var featureInjectorCache = new CachingAudioFeatureInjectorFactory(LoggerFactory, Cache);
|
||||
consumers.Add(await featureInjectorCache.Get(spotifyFactory));
|
||||
|
||||
var cacheWriter = new CacheWriterFactory(Cache, LoggerFactory);
|
||||
consumers.Add(await cacheWriter.Get());
|
||||
|
||||
var pub = new PublisherFactory(Subscriber, LoggerFactory);
|
||||
consumers.Add(await pub.Get());
|
||||
consumers.Add(await AudioFeatureInjectorFactory.Get(spotifyFactory));
|
||||
consumers.Add(await CacheWriterFactory.Get());
|
||||
consumers.Add(await PublisherFactory.Get());
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(dbWatcher.User.LastFmUsername))
|
||||
{
|
||||
if (LastAuth is null) throw new ArgumentNullException("No Last Auth Injected");
|
||||
|
||||
var client = new LastfmClient(LastAuth);
|
||||
|
||||
var playCount = new PlayCounterFactory(LoggerFactory, client: client, creds: new() { Username = dbWatcher.User.LastFmUsername });
|
||||
consumers.Add(await playCount.Get());
|
||||
consumers.Add(await PlayCounterFactory.Get(creds: new() { Username = dbWatcher.User.LastFmUsername }));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4,15 +4,13 @@ using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using IF.Lastfm.Core.Api;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Selector.Cache;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Selector.CLI
|
||||
{
|
||||
@ -21,15 +19,12 @@ namespace Selector.CLI
|
||||
private const string ConfigInstanceKey = "localconfig";
|
||||
|
||||
private readonly ILogger<LocalWatcherService> Logger;
|
||||
private readonly ILoggerFactory LoggerFactory;
|
||||
private readonly RootOptions Config;
|
||||
private readonly IWatcherFactory WatcherFactory;
|
||||
private readonly IWatcherCollectionFactory WatcherCollectionFactory;
|
||||
private readonly IRefreshTokenFactoryProvider SpotifyFactory;
|
||||
private readonly LastAuth LastAuth;
|
||||
|
||||
private readonly IDatabaseAsync Cache;
|
||||
private readonly ISubscriber Subscriber;
|
||||
|
||||
private readonly IServiceProvider ServiceProvider;
|
||||
|
||||
private Dictionary<string, IWatcherCollection> Watchers { get; set; } = new();
|
||||
|
||||
@ -37,21 +32,20 @@ namespace Selector.CLI
|
||||
IWatcherFactory watcherFactory,
|
||||
IWatcherCollectionFactory watcherCollectionFactory,
|
||||
IRefreshTokenFactoryProvider spotifyFactory,
|
||||
ILoggerFactory loggerFactory,
|
||||
IOptions<RootOptions> config,
|
||||
LastAuth lastAuth = null,
|
||||
IDatabaseAsync cache = null,
|
||||
ISubscriber subscriber = null
|
||||
|
||||
IServiceProvider serviceProvider,
|
||||
|
||||
ILogger<LocalWatcherService> logger,
|
||||
IOptions<RootOptions> config
|
||||
) {
|
||||
Logger = loggerFactory.CreateLogger<LocalWatcherService>();
|
||||
LoggerFactory = loggerFactory;
|
||||
Logger = logger;
|
||||
Config = config.Value;
|
||||
|
||||
WatcherFactory = watcherFactory;
|
||||
WatcherCollectionFactory = watcherCollectionFactory;
|
||||
SpotifyFactory = spotifyFactory;
|
||||
LastAuth = lastAuth;
|
||||
Cache = cache;
|
||||
Subscriber = subscriber;
|
||||
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public async Task StartAsync(CancellationToken cancellationToken)
|
||||
@ -111,34 +105,25 @@ namespace Selector.CLI
|
||||
switch(consumer)
|
||||
{
|
||||
case Consumers.AudioFeatures:
|
||||
var featureInjector = new AudioFeatureInjectorFactory(LoggerFactory);
|
||||
consumers.Add(await featureInjector.Get(spotifyFactory));
|
||||
consumers.Add(await ServiceProvider.GetService<AudioFeatureInjectorFactory>().Get(spotifyFactory));
|
||||
break;
|
||||
|
||||
case Consumers.AudioFeaturesCache:
|
||||
var featureInjectorCache = new CachingAudioFeatureInjectorFactory(LoggerFactory, Cache);
|
||||
consumers.Add(await featureInjectorCache.Get(spotifyFactory));
|
||||
consumers.Add(await ServiceProvider.GetService<CachingAudioFeatureInjectorFactory>().Get(spotifyFactory));
|
||||
break;
|
||||
|
||||
case Consumers.CacheWriter:
|
||||
var cacheWriter = new CacheWriterFactory(Cache, LoggerFactory);
|
||||
consumers.Add(await cacheWriter.Get());
|
||||
consumers.Add(await ServiceProvider.GetService<CacheWriterFactory>().Get());
|
||||
break;
|
||||
|
||||
case Consumers.Publisher:
|
||||
var pub = new PublisherFactory(Subscriber, LoggerFactory);
|
||||
consumers.Add(await pub.Get());
|
||||
consumers.Add(await ServiceProvider.GetService<PublisherFactory>().Get());
|
||||
break;
|
||||
|
||||
case Consumers.PlayCounter:
|
||||
if(!string.IsNullOrWhiteSpace(watcherOption.LastFmUsername))
|
||||
{
|
||||
if(LastAuth is null) throw new ArgumentNullException("No Last Auth Injected");
|
||||
|
||||
var client = new LastfmClient(LastAuth);
|
||||
|
||||
var playCount = new PlayCounterFactory(LoggerFactory, client: client, creds: new(){ Username = watcherOption.LastFmUsername });
|
||||
consumers.Add(await playCount.Get());
|
||||
consumers.Add(await ServiceProvider.GetService<PlayCounterCachingFactory>().Get(creds: new() { Username = watcherOption.LastFmUsername }));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace Selector.CLI
|
||||
public static string FormatKeys(string[] args) => string.Join(":", args);
|
||||
}
|
||||
|
||||
class RootOptions
|
||||
public class RootOptions
|
||||
{
|
||||
public const string Key = "Selector";
|
||||
|
||||
@ -42,12 +42,12 @@ namespace Selector.CLI
|
||||
public EqualityChecker Equality { get; set; } = EqualityChecker.Uri;
|
||||
}
|
||||
|
||||
enum EqualityChecker
|
||||
public enum EqualityChecker
|
||||
{
|
||||
Uri, String
|
||||
}
|
||||
|
||||
class WatcherOptions
|
||||
public class WatcherOptions
|
||||
{
|
||||
public const string Key = "Watcher";
|
||||
|
||||
@ -56,7 +56,7 @@ namespace Selector.CLI
|
||||
public List<WatcherInstanceOptions> Instances { get; set; } = new();
|
||||
}
|
||||
|
||||
class WatcherInstanceOptions
|
||||
public class WatcherInstanceOptions
|
||||
{
|
||||
public const string Key = "Instances";
|
||||
|
||||
@ -73,19 +73,19 @@ namespace Selector.CLI
|
||||
#nullable disable
|
||||
}
|
||||
|
||||
enum Consumers
|
||||
public enum Consumers
|
||||
{
|
||||
AudioFeatures, AudioFeaturesCache, CacheWriter, Publisher, PlayCounter
|
||||
}
|
||||
|
||||
class DatabaseOptions {
|
||||
public class DatabaseOptions {
|
||||
public const string Key = "Database";
|
||||
|
||||
public bool Enabled { get; set; } = false;
|
||||
public string ConnectionString { get; set; }
|
||||
}
|
||||
|
||||
class RedisOptions
|
||||
public class RedisOptions
|
||||
{
|
||||
public const string Key = "Redis";
|
||||
|
||||
|
@ -11,12 +11,12 @@ using NLog.Extensions.Logging;
|
||||
|
||||
using Selector.Model;
|
||||
using Selector.Cache;
|
||||
using Selector.Cache.Extensions;
|
||||
using IF.Lastfm.Core.Api;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Selector.CLI
|
||||
{
|
||||
class Program
|
||||
public static class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
@ -55,7 +55,8 @@ namespace Selector.CLI
|
||||
Console.WriteLine("> Adding Last.fm credentials...");
|
||||
|
||||
var lastAuth = new LastAuth(config.LastfmClient, config.LastfmSecret);
|
||||
services.AddSingleton<LastAuth>(lastAuth);
|
||||
services.AddSingleton(lastAuth);
|
||||
services.AddTransient(sp => new LastfmClient(sp.GetService<LastAuth>()));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -74,25 +75,6 @@ namespace Selector.CLI
|
||||
}
|
||||
}
|
||||
|
||||
public static void ConfigureRedis(RootOptions config, IServiceCollection services)
|
||||
{
|
||||
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.AddTransient<IDatabaseAsync>(services => services.GetService<ConnectionMultiplexer>().GetDatabase());
|
||||
services.AddTransient<ISubscriber>(services => services.GetService<ConnectionMultiplexer>().GetSubscriber());
|
||||
}
|
||||
}
|
||||
|
||||
public static void ConfigureEqual(RootOptions config, IServiceCollection services)
|
||||
{
|
||||
switch (config.Equality)
|
||||
@ -119,8 +101,9 @@ namespace Selector.CLI
|
||||
|
||||
Console.WriteLine("> Adding Services...");
|
||||
// SERVICES
|
||||
services.AddCachingConsumerFactories();
|
||||
|
||||
services.AddSingleton<IWatcherFactory, WatcherFactory>();
|
||||
services.AddSingleton<IAudioFeatureInjectorFactory, AudioFeatureInjectorFactory>();
|
||||
services.AddSingleton<IWatcherCollectionFactory, WatcherCollectionFactory>();
|
||||
// For generating spotify clients
|
||||
//services.AddSingleton<IRefreshTokenFactoryProvider, RefreshTokenFactoryProvider>();
|
||||
@ -128,7 +111,10 @@ namespace Selector.CLI
|
||||
|
||||
ConfigureLastFm(config, services);
|
||||
ConfigureDb(config, services);
|
||||
ConfigureRedis(config, services);
|
||||
|
||||
if (config.RedisOptions.Enabled)
|
||||
services.AddRedisServices(config.RedisOptions.ConnectionString);
|
||||
|
||||
ConfigureEqual(config, services);
|
||||
|
||||
// HOSTED SERVICES
|
||||
|
@ -8,13 +8,8 @@ using SpotifyAPI.Web;
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Selector.Cache
|
||||
{
|
||||
public interface ICachingAudioFeatureInjectorFactory
|
||||
{
|
||||
public Task<IConsumer> Get(ISpotifyConfigFactory spotifyFactory, IPlayerWatcher watcher);
|
||||
}
|
||||
|
||||
public class CachingAudioFeatureInjectorFactory: ICachingAudioFeatureInjectorFactory {
|
||||
{
|
||||
public class CachingAudioFeatureInjectorFactory: IAudioFeatureInjectorFactory {
|
||||
|
||||
private readonly ILoggerFactory LoggerFactory;
|
||||
private readonly IDatabaseAsync Db;
|
||||
|
52
Selector.Cache/Consumer/Factory/PlayCounterCachingFactory.cs
Normal file
52
Selector.Cache/Consumer/Factory/PlayCounterCachingFactory.cs
Normal file
@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using StackExchange.Redis;
|
||||
using IF.Lastfm.Core.Api;
|
||||
|
||||
namespace Selector.Cache
|
||||
{
|
||||
public class PlayCounterCachingFactory: IPlayCounterFactory
|
||||
{
|
||||
private readonly ILoggerFactory LoggerFactory;
|
||||
private readonly IDatabaseAsync Cache;
|
||||
private readonly LastfmClient Client;
|
||||
private readonly LastFmCredentials Creds;
|
||||
|
||||
public PlayCounterCachingFactory(
|
||||
ILoggerFactory loggerFactory,
|
||||
IDatabaseAsync cache,
|
||||
LastfmClient client = null,
|
||||
LastFmCredentials creds = null)
|
||||
{
|
||||
LoggerFactory = loggerFactory;
|
||||
Cache = cache;
|
||||
Client = client;
|
||||
Creds = creds;
|
||||
}
|
||||
|
||||
public async Task<IConsumer> Get(LastfmClient fmClient = null, LastFmCredentials creds = null, IPlayerWatcher watcher = null)
|
||||
{
|
||||
var client = fmClient ?? Client;
|
||||
|
||||
if (client is null)
|
||||
{
|
||||
throw new ArgumentNullException("No Last.fm client provided");
|
||||
}
|
||||
|
||||
return new PlayCounterCaching(
|
||||
watcher,
|
||||
client.Track,
|
||||
client.Album,
|
||||
client.Artist,
|
||||
client.User,
|
||||
Cache,
|
||||
credentials: creds ?? Creds,
|
||||
logger: LoggerFactory.CreateLogger<PlayCounterCaching>()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
61
Selector.Cache/Consumer/PlayCounterCaching.cs
Normal file
61
Selector.Cache/Consumer/PlayCounterCaching.cs
Normal file
@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using IF.Lastfm.Core.Api;
|
||||
using StackExchange.Redis;
|
||||
using SpotifyAPI.Web;
|
||||
|
||||
namespace Selector.Cache
|
||||
{
|
||||
public class PlayCounterCaching: PlayCounter
|
||||
{
|
||||
private readonly IDatabaseAsync Db;
|
||||
public TimeSpan CacheExpiry { get; set; } = TimeSpan.FromDays(14);
|
||||
|
||||
public PlayCounterCaching(
|
||||
IPlayerWatcher watcher,
|
||||
ITrackApi trackClient,
|
||||
IAlbumApi albumClient,
|
||||
IArtistApi artistClient,
|
||||
IUserApi userClient,
|
||||
IDatabaseAsync db,
|
||||
LastFmCredentials credentials = null,
|
||||
ILogger<PlayCounterCaching> logger = null,
|
||||
CancellationToken token = default
|
||||
) : base(watcher, trackClient, albumClient, artistClient, userClient, credentials, logger, token)
|
||||
{
|
||||
Db = db;
|
||||
|
||||
NewPlayCount += CacheCallback;
|
||||
}
|
||||
|
||||
public void CacheCallback(object sender, PlayCount e)
|
||||
{
|
||||
Task.Run(() => { return AsyncCacheCallback(e); }, CancelToken);
|
||||
}
|
||||
|
||||
public async Task AsyncCacheCallback(PlayCount e)
|
||||
{
|
||||
var track = e.ListeningEvent.Current.Item as FullTrack;
|
||||
Logger.LogTrace($"Caching play count for [{track.DisplayString()}]");
|
||||
|
||||
var tasks = new Task[]
|
||||
{
|
||||
Db.StringSetAsync(Key.TrackPlayCount(track.Name, track.Artists[0].Name), e.Track, expiry: CacheExpiry),
|
||||
Db.StringSetAsync(Key.AlbumPlayCount(track.Album.Name, track.Album.Artists[0].Name), e.Album, expiry: CacheExpiry),
|
||||
Db.StringSetAsync(Key.ArtistPlayCount(track.Artists[0].Name), e.Artist, expiry: CacheExpiry),
|
||||
Db.StringSetAsync(Key.UserPlayCount(e.Username), e.User, expiry: CacheExpiry),
|
||||
};
|
||||
|
||||
await Task.WhenAll(tasks);
|
||||
|
||||
Logger.LogDebug($"Cached audio feature for [{track.DisplayString()}]");
|
||||
}
|
||||
}
|
||||
}
|
37
Selector.Cache/Extensions/ServiceExtensions.cs
Normal file
37
Selector.Cache/Extensions/ServiceExtensions.cs
Normal file
@ -0,0 +1,37 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using StackExchange.Redis;
|
||||
|
||||
namespace Selector.Cache.Extensions
|
||||
{
|
||||
public static class ServiceExtensions
|
||||
{
|
||||
public static void AddRedisServices(this IServiceCollection services, string connectionStr)
|
||||
{
|
||||
Console.WriteLine("> Configuring Redis...");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(connectionStr))
|
||||
{
|
||||
Console.WriteLine("> No Redis configuration string provided, exiting...");
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
var connMulti = ConnectionMultiplexer.Connect(connectionStr);
|
||||
services.AddSingleton(connMulti);
|
||||
services.AddTransient<IDatabaseAsync>(services => services.GetService<ConnectionMultiplexer>().GetDatabase());
|
||||
services.AddTransient<ISubscriber>(services => services.GetService<ConnectionMultiplexer>().GetSubscriber());
|
||||
}
|
||||
|
||||
public static void AddCachingConsumerFactories(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IAudioFeatureInjectorFactory, AudioFeatureInjectorFactory>();
|
||||
services.AddTransient<IPlayCounterFactory, PlayCounterCachingFactory>();
|
||||
|
||||
services.AddTransient<ICacheWriterFactory, CacheWriterFactory>();
|
||||
services.AddTransient<IPublisherFactory, PublisherFactory>();
|
||||
}
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@ namespace Selector.Cache
|
||||
public const string TrackName = "Track";
|
||||
public const string AlbumName = "Album";
|
||||
public const string ArtistName = "Artist";
|
||||
public const string UserName = "User";
|
||||
|
||||
public const string AudioFeatureName = "AudioFeature";
|
||||
public const string PlayCountName = "PlayCount";
|
||||
@ -30,6 +31,7 @@ namespace Selector.Cache
|
||||
public static string TrackPlayCount(string name, string artist) => Namespace(TrackName, artist, name, PlayCountName);
|
||||
public static string AlbumPlayCount(string name, string artist) => Namespace(AlbumName, artist, name, PlayCountName);
|
||||
public static string ArtistPlayCount(string name) => Namespace(ArtistName, name, PlayCountName);
|
||||
public static string UserPlayCount(string username) => Namespace(UserName, username, PlayCountName);
|
||||
|
||||
public static string WatcherReserved(int id) => Namespace(WatcherName, id.ToString(), ReservedName);
|
||||
|
||||
|
30
Selector.Model/Extensions/ServiceExtensions.cs
Normal file
30
Selector.Model/Extensions/ServiceExtensions.cs
Normal file
@ -0,0 +1,30 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using Selector.Model.Authorisation;
|
||||
|
||||
namespace Selector.Model.Extensions
|
||||
{
|
||||
public static class ServiceExtensions
|
||||
{
|
||||
public static void AddAuthorisationHandlers(this IServiceCollection services)
|
||||
{
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.FallbackPolicy = new AuthorizationPolicyBuilder()
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
});
|
||||
services.AddScoped<IAuthorizationHandler, WatcherIsOwnerAuthHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, WatcherIsAdminAuthHandler>();
|
||||
|
||||
services.AddScoped<IAuthorizationHandler, UserIsSelfAuthHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, UserIsAdminAuthHandler>();
|
||||
}
|
||||
}
|
||||
}
|
@ -13,13 +13,12 @@ using Microsoft.AspNetCore.Identity;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
using StackExchange.Redis;
|
||||
|
||||
using Selector.Web.Service;
|
||||
using Selector.Web.Hubs;
|
||||
using Selector.Model;
|
||||
using Selector.Model.Authorisation;
|
||||
using Selector.Model.Extensions;
|
||||
using Selector.Cache;
|
||||
using Selector.Cache.Extensions;
|
||||
|
||||
namespace Selector.Web
|
||||
{
|
||||
@ -93,35 +92,10 @@ namespace Selector.Web
|
||||
options.SlidingExpiration = true;
|
||||
});
|
||||
|
||||
// AUTH
|
||||
services.AddAuthorization(options =>
|
||||
{
|
||||
options.FallbackPolicy = new AuthorizationPolicyBuilder()
|
||||
.RequireAuthenticatedUser()
|
||||
.Build();
|
||||
});
|
||||
services.AddScoped<IAuthorizationHandler, WatcherIsOwnerAuthHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, WatcherIsAdminAuthHandler>();
|
||||
services.AddAuthorisationHandlers();
|
||||
|
||||
services.AddScoped<IAuthorizationHandler, UserIsSelfAuthHandler>();
|
||||
services.AddSingleton<IAuthorizationHandler, UserIsAdminAuthHandler>();
|
||||
|
||||
// REDIS
|
||||
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.AddTransient<IDatabaseAsync>(services => services.GetService<ConnectionMultiplexer>().GetDatabase());
|
||||
services.AddTransient<ISubscriber>(services => services.GetService<ConnectionMultiplexer>().GetSubscriber());
|
||||
}
|
||||
services.AddRedisServices(config.RedisOptions.ConnectionString);
|
||||
|
||||
services.AddSingleton<IRefreshTokenFactoryProvider, CachingRefreshTokenFactoryProvider>();
|
||||
services.AddSingleton<AudioFeaturePuller>();
|
||||
|
@ -10,7 +10,7 @@ namespace Selector
|
||||
{
|
||||
public interface IAudioFeatureInjectorFactory
|
||||
{
|
||||
public Task<IConsumer> Get(ISpotifyConfigFactory spotifyFactory, IPlayerWatcher watcher);
|
||||
public Task<IConsumer> Get(ISpotifyConfigFactory spotifyFactory, IPlayerWatcher watcher = null);
|
||||
}
|
||||
|
||||
public class AudioFeatureInjectorFactory: IAudioFeatureInjectorFactory {
|
||||
|
@ -123,13 +123,19 @@ namespace Selector
|
||||
|
||||
Logger.LogDebug($"Adding Last.fm data [{e.Id}/{e.SpotifyUsername}/{Credentials.Username}] [{track.DisplayString()}], track: {trackCount}, album: {albumCount}, artist: {artistCount}, user: {userCount}");
|
||||
|
||||
OnNewPlayCount(new()
|
||||
PlayCount playCount = new()
|
||||
{
|
||||
Track = trackCount,
|
||||
Album = albumCount,
|
||||
Artist = artistCount,
|
||||
User = userCount,
|
||||
});
|
||||
ListeningEvent = e
|
||||
};
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(Credentials.Username))
|
||||
playCount.Username = Credentials.Username;
|
||||
|
||||
OnNewPlayCount(playCount);
|
||||
}
|
||||
else if (e.Current.Item is FullEpisode episode)
|
||||
{
|
||||
@ -181,6 +187,8 @@ namespace Selector
|
||||
public int? Album { get; set; }
|
||||
public int? Artist { get; set; }
|
||||
public int? User { get; set; }
|
||||
public string Username { get; set; }
|
||||
public ListeningChangeEventArgs ListeningEvent { get; set; }
|
||||
}
|
||||
|
||||
public class LastFmCredentials
|
||||
|
16
Selector/Extensions/ServiceExtensions.cs
Normal file
16
Selector/Extensions/ServiceExtensions.cs
Normal file
@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Selector.Extensions
|
||||
{
|
||||
public static class ServiceExtensions
|
||||
{
|
||||
public static void AddConsumerFactories(this IServiceCollection services)
|
||||
{
|
||||
services.AddTransient<IAudioFeatureInjectorFactory, AudioFeatureInjectorFactory>();
|
||||
services.AddTransient<IPlayCounterFactory, PlayCounterFactory>();
|
||||
}
|
||||
}
|
||||
}
|
13
Selector/Watcher/Context/Interfaces/IWatcherContext.cs
Normal file
13
Selector/Watcher/Context/Interfaces/IWatcherContext.cs
Normal file
@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Selector
|
||||
{
|
||||
public interface IWatcherContext
|
||||
{
|
||||
void AddConsumer(IConsumer consumer);
|
||||
void Start();
|
||||
void Stop();
|
||||
}
|
||||
}
|
@ -7,7 +7,7 @@ using System.Threading.Tasks;
|
||||
|
||||
namespace Selector
|
||||
{
|
||||
public class WatcherContext: IDisposable
|
||||
public class WatcherContext: IDisposable, IWatcherContext
|
||||
{
|
||||
public IWatcher Watcher { get; set; }
|
||||
private List<IConsumer> Consumers { get; set; } = new();
|
Loading…
Reference in New Issue
Block a user