added watcherfactory, theoretically working watcher service

This commit is contained in:
andy 2021-10-12 23:29:05 +01:00
parent 1694f8e3a9
commit b5956ef4a0
12 changed files with 178 additions and 25 deletions

View File

@ -41,6 +41,7 @@ namespace Selector.CLI
public WatcherType Type { get; set; } = WatcherType.Player;
#nullable enable
public string? PlaylistUri { get; set; }
public string? WatcherCollection { get; set; }
#nullable disable
}

View File

@ -27,8 +27,9 @@ namespace Selector.CLI
});
// SERVICES
//services.AddTransient<IWatcherFactory, PlayerWatcher>();
//services.AddTransient<IWatcherCollection, WatcherCollection>();
services.AddSingleton<IWatcherFactory, WatcherFactory>();
services.AddSingleton<IWatcherCollectionFactory, WatcherCollectionFactory>();
// For generating spotify clients
services.AddSingleton<IRefreshTokenFactoryProvider, RefreshTokenFactoryProvider>();
switch(context.Configuration.GetValue<EqualityChecker>("selector:equality"))

View File

@ -0,0 +1,10 @@
{
"profiles": {
"Selector.CLI": {
"commandName": "Project",
"environmentVariables": {
"DOTNET_ENVIRONMENT": "Development"
}
}
}
}

View File

@ -22,6 +22,9 @@
</ItemGroup>
<ItemGroup>
<None Update="appsettings.Development.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="appsettings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>

View File

@ -5,6 +5,7 @@ using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
@ -13,28 +14,103 @@ namespace Selector.CLI
{
class WatcherService : IHostedService
{
private const string ConfigInstanceKey = "localconfig";
private readonly ILogger<WatcherService> Logger;
private readonly RootOptions Config;
private readonly IRefreshTokenFactoryProvider TokenFactoryProvider;
private readonly IWatcherFactory WatcherFactory;
private readonly IWatcherCollectionFactory WatcherCollectionFactory;
private readonly IRefreshTokenFactoryProvider SpotifyFactory;
private Dictionary<string, IWatcherCollection> Watchers { get; set; } = new();
public WatcherService(IRefreshTokenFactoryProvider tokenFactoryProvider, ILogger<WatcherService> logger, IOptions<RootOptions> config)
{
public WatcherService(
IWatcherFactory watcherFactory,
IWatcherCollectionFactory watcherCollectionFactory,
IRefreshTokenFactoryProvider spotifyFactory,
ILogger<WatcherService> logger,
IOptions<RootOptions> config
) {
Logger = logger;
Config = config.Value;
TokenFactoryProvider = tokenFactoryProvider;
WatcherFactory = watcherFactory;
WatcherCollectionFactory = watcherCollectionFactory;
SpotifyFactory = spotifyFactory;
TokenFactoryProvider.Initialise(Config.ClientId, Config.ClientSecret);
SpotifyFactory.Initialise(Config.ClientId, Config.ClientSecret);
}
public Task StartAsync(CancellationToken cancellationToken)
public async Task StartAsync(CancellationToken cancellationToken)
{
Logger.LogInformation("Starting up");
Config.WatcherOptions.Instances.ForEach(i => Logger.LogInformation($"Config: {i.Type}"));
Logger.LogInformation("Loading config instances...");
var watcherIndices = await InitialiseConfigInstances();
return Task.CompletedTask;
Logger.LogInformation($"Starting {watcherIndices.Count()} affected watcher collection(s)...");
StartWatcherCollections(watcherIndices);
}
private async Task<IEnumerable<string>> InitialiseConfigInstances()
{
var indices = new HashSet<string>();
foreach (var watcherOption in Config.WatcherOptions.Instances)
{
var logMsg = new StringBuilder();
if (!string.IsNullOrWhiteSpace(watcherOption.Name))
{
logMsg.Append($"Creating {watcherOption.Name} watcher [{watcherOption.Type}]");
}
else
{
logMsg.Append($"Creating new {watcherOption.Type} watcher");
}
if (!string.IsNullOrWhiteSpace(watcherOption.PlaylistUri)) logMsg.Append($" [{ watcherOption.PlaylistUri}]");
Logger.LogInformation(logMsg.ToString());
var watcherCollectionIdx = watcherOption.WatcherCollection ?? ConfigInstanceKey;
indices.Add(watcherCollectionIdx);
if (!Watchers.ContainsKey(watcherCollectionIdx))
Watchers[watcherCollectionIdx] = WatcherCollectionFactory.Get();
var watcherCollection = Watchers[watcherCollectionIdx];
Logger.LogDebug("Getting Spotify factory");
var spotifyFactory = await SpotifyFactory.GetFactory(watcherOption.RefreshKey);
IWatcher watcher = null;
switch(watcherOption.Type)
{
case WatcherType.Player:
watcher = await WatcherFactory.Get<PlayerWatcher>(spotifyFactory, watcherOption.PollPeriod);
break;
case WatcherType.Playlist:
throw new NotImplementedException("Playlist watchers not implemented");
break;
}
watcherCollection.Add(watcher);
}
return indices;
}
private void StartWatcherCollections(IEnumerable<string> indices)
{
foreach (var index in indices)
{
try
{
Watchers[index].Start();
}
catch (KeyNotFoundException)
{
Logger.LogError($"Unable to retrieve watcher collection [{index}] when starting");
}
}
}
public Task StopAsync(CancellationToken cancellationToken)

View File

@ -6,12 +6,9 @@
"Watcher": {
"Instances": [
{
"name": "sarsoo",
"type": "player"
},
{
"name": "andy",
"type": "playlist"
"name": "player watcher",
"type": "player",
"pollperiod": 1000
}
]
}

View File

@ -20,7 +20,7 @@ namespace Selector
ClientSecret = clientSecret;
}
public bool Initialised => string.IsNullOrWhiteSpace(ClientId) || string.IsNullOrWhiteSpace(ClientSecret);
public bool Initialised => !string.IsNullOrWhiteSpace(ClientId) && !string.IsNullOrWhiteSpace(ClientSecret);
public Task<RefreshTokenFactory> GetFactory(string refreshToken)
{

View File

@ -1,11 +1,13 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
namespace Selector
{
public interface IWatcherFactory
{
public IWatcher Create();
public Task<IWatcher> Get<T>(ISpotifyConfigFactory spotifyFactory, int pollPeriod)
where T : class, IWatcher;
}
}

View File

@ -0,0 +1,7 @@
namespace Selector
{
public interface IWatcherCollectionFactory
{
public IWatcherCollection Get();
}
}

View File

@ -0,0 +1,19 @@
using Microsoft.Extensions.Logging;
namespace Selector
{
public class WatcherCollectionFactory: IWatcherCollectionFactory
{
private readonly ILoggerFactory LoggerFactory;
public WatcherCollectionFactory(ILoggerFactory loggerFactory)
{
LoggerFactory = loggerFactory;
}
public IWatcherCollection Get()
{
return new WatcherCollection(LoggerFactory.CreateLogger<WatcherCollection>());
}
}
}

View File

@ -31,6 +31,10 @@ namespace Selector
IsRunning = true;
TokenSource = new();
Task = Watcher.Watch(TokenSource.Token);
Task.ContinueWith(t =>
{
if (t.Exception != null) throw t.Exception;
}, TaskContinuationOptions.OnlyOnFaulted);
}
public void Stop()

View File

@ -1,14 +1,47 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using SpotifyAPI.Web;
namespace Selector
{
//class PlayerWatcherFactory : IWatcherFactory
//{
// public IWatcher Create()
// {
public class WatcherFactory : IWatcherFactory {
private readonly ILoggerFactory LoggerFactory;
private readonly IEqual Equal;
public WatcherFactory(ILoggerFactory loggerFactory, IEqual equal)
{
LoggerFactory = loggerFactory;
Equal = equal;
}
public async Task<IWatcher> Get<T>(ISpotifyConfigFactory spotifyFactory, int pollPeriod = 3000)
where T : class, IWatcher
{
if(typeof(T).IsAssignableFrom(typeof(PlayerWatcher)))
{
var config = await spotifyFactory.GetConfig();
var client = new SpotifyClient(config);
return new PlayerWatcher(
client.Player,
Equal,
LoggerFactory?.CreateLogger<PlayerWatcher>(),
pollPeriod: pollPeriod
);
}
//else if (typeof(T).IsAssignableFrom(typeof(PlaylistWatcher)))
//{
// }
//}
else
{
throw new ArgumentException("Type unsupported");
}
}
}
}