adding manager functionality

This commit is contained in:
andy 2021-10-07 22:09:10 +01:00
parent 28b7b954c1
commit 7d5ab4477d
12 changed files with 224 additions and 30 deletions

View File

@ -63,7 +63,7 @@ namespace Selector.Tests
public void TrackEquality(FullTrack track1, FullTrack track2, bool shouldEqual) public void TrackEquality(FullTrack track1, FullTrack track2, bool shouldEqual)
{ {
var eq = Equal.String(); var eq = Equal.String();
eq.IsEqual<FullTrack>(track1, track2).Should().Be(shouldEqual); eq.IsEqual(track1, track2).Should().Be(shouldEqual);
} }
public static IEnumerable<object[]> AlbumData => public static IEnumerable<object[]> AlbumData =>
@ -106,7 +106,7 @@ namespace Selector.Tests
public void AlbumEquality(SimpleAlbum album1, SimpleAlbum album2, bool shouldEqual) public void AlbumEquality(SimpleAlbum album1, SimpleAlbum album2, bool shouldEqual)
{ {
var eq = Equal.String(); var eq = Equal.String();
eq.IsEqual<SimpleAlbum>(album1, album2).Should().Be(shouldEqual); eq.IsEqual(album1, album2).Should().Be(shouldEqual);
} }
public static IEnumerable<object[]> ArtistData => public static IEnumerable<object[]> ArtistData =>
@ -131,7 +131,7 @@ namespace Selector.Tests
public void ArtistEquality(SimpleArtist artist1, SimpleArtist artist2, bool shouldEqual) public void ArtistEquality(SimpleArtist artist1, SimpleArtist artist2, bool shouldEqual)
{ {
var eq = Equal.String(); var eq = Equal.String();
eq.IsEqual<SimpleArtist>(artist1, artist2).Should().Be(shouldEqual); eq.IsEqual(artist1, artist2).Should().Be(shouldEqual);
} }
public static IEnumerable<object[]> EpisodeData => public static IEnumerable<object[]> EpisodeData =>
@ -156,7 +156,7 @@ namespace Selector.Tests
public void EpisodeEquality(FullEpisode episode1, FullEpisode episode2, bool shouldEqual) public void EpisodeEquality(FullEpisode episode1, FullEpisode episode2, bool shouldEqual)
{ {
var eq = Equal.String(); var eq = Equal.String();
eq.IsEqual<FullEpisode>(episode1, episode2).Should().Be(shouldEqual); eq.IsEqual(episode1, episode2).Should().Be(shouldEqual);
} }
} }
} }

56
Selector.Tests/Manager.cs Normal file
View File

@ -0,0 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Xunit;
using Moq;
using FluentAssertions;
using SpotifyAPI.Web;
using Selector;
using System.Threading.Tasks;
namespace Selector.Tests
{
public class ManagerTests
{
[Fact]
public void Count()
{
var manager = new Manager();
var watcherMock = new Mock<IWatcher>();
manager.Add(watcherMock.Object);
manager.Add(watcherMock.Object);
manager.Add(watcherMock.Object);
manager.Count.Should().Be(3);
}
[Fact]
public void StartAndStop()
{
var manager = new Manager();
var watcherMock = new Mock<IWatcher>();
manager.Add(watcherMock.Object);
manager.Count.Should().Be(1);
manager.Start();
manager.IsRunning.Should().BeTrue();
manager.Running.Count().Should().Be(1);
var context = manager.Running.First();
manager.Stop();
manager.IsRunning.Should().BeFalse();
context.IsRunning.Should().BeFalse();
manager.Running.Count().Should().Be(0);
manager.TokenSources.First().IsCancellationRequested.Should().BeTrue();
}
}
}

View File

@ -6,6 +6,8 @@ using FluentAssertions;
using SpotifyAPI.Web; using SpotifyAPI.Web;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using Xunit.Sdk;
namespace Selector.Tests namespace Selector.Tests
{ {
@ -203,11 +205,32 @@ namespace Selector.Tests
toNotRaise.ForEach(r => monitoredWatcher.Should().NotRaise(r)); toNotRaise.ForEach(r => monitoredWatcher.Should().NotRaise(r));
} }
[Theory]
[InlineData(1000, 3500, 4)]
[InlineData(500, 3800, 8)]
public async void Watch(int pollPeriod, int execTime, int numberOfCalls)
{
var spotMock = new Mock<IPlayerClient>();
var eq = new UriEqual();
var watch = new PlayerWatcher(spotMock.Object, eq)
{
PollPeriod = pollPeriod
};
var tokenSource = new CancellationTokenSource();
var task = watch.Watch(tokenSource.Token);
await Task.Delay(execTime);
tokenSource.Cancel();
spotMock.Verify(s => s.GetCurrentPlayback(), Times.Exactly(numberOfCalls));
}
// [Fact] // [Fact]
// public async void Auth() // public async void Auth()
// { // {
// var spot = new SpotifyClient(""); // var spot = new SpotifyClient("");
// var eq = new UriEquality(); // var eq = new UriEqual();
// var watch = new PlayerWatcher(spot.Player, eq); // var watch = new PlayerWatcher(spot.Player, eq);
// var token = new CancellationTokenSource(); // var token = new CancellationTokenSource();

View File

@ -1,10 +0,0 @@
using System;
namespace Selector
{
class Playable
{
public Type Type;
public object Obj;
}
}

View File

@ -34,10 +34,7 @@ namespace Selector
public void Add(CurrentlyPlayingContext item) => Add(item, DateHelper.FromUnixMilli(item.Timestamp)); public void Add(CurrentlyPlayingContext item) => Add(item, DateHelper.FromUnixMilli(item.Timestamp));
public void Add(CurrentlyPlayingContext item, DateTime timestamp) public void Add(CurrentlyPlayingContext item, DateTime timestamp)
{ {
recentlyPlayed.Add(new TimelineItem<CurrentlyPlayingContext>(){ recentlyPlayed.Add(TimelineItem<CurrentlyPlayingContext>.From(item, timestamp));
Item = item,
Time = timestamp
});
if (timestamp < recentlyPlayed.Last().Time && SortOnBackDate) if (timestamp < recentlyPlayed.Last().Time && SortOnBackDate)
{ {

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq.Expressions;
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -8,13 +9,13 @@ namespace Selector
{ {
public abstract class BaseWatcher: IWatcher public abstract class BaseWatcher: IWatcher
{ {
public abstract Task WatchOne(); public abstract Task WatchOne(CancellationToken token);
public async Task Watch(CancellationToken cancelToken) public async Task Watch(CancellationToken cancelToken)
{ {
while (!cancelToken.IsCancellationRequested) while (true) {
{ cancelToken.ThrowIfCancellationRequested();
await WatchOne(); await WatchOne(cancelToken);
await Task.Delay(PollPeriod); await Task.Delay(PollPeriod);
} }
} }

View File

@ -1,5 +1,4 @@
using System; using System;
using System.Collections.Generic;
using SpotifyAPI.Web; using SpotifyAPI.Web;
namespace Selector namespace Selector
@ -15,5 +14,8 @@ namespace Selector
public event EventHandler<ListeningChangeEventArgs> VolumeChange; public event EventHandler<ListeningChangeEventArgs> VolumeChange;
public event EventHandler<ListeningChangeEventArgs> DeviceChange; public event EventHandler<ListeningChangeEventArgs> DeviceChange;
public event EventHandler<ListeningChangeEventArgs> PlayingChange; public event EventHandler<ListeningChangeEventArgs> PlayingChange;
public CurrentlyPlayingContext Live { get; }
public PlayerTimeline Past { get; }
} }
} }

View File

@ -1,13 +1,11 @@
using System;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using SpotifyAPI.Web;
namespace Selector namespace Selector
{ {
public interface IWatcher public interface IWatcher
{ {
public Task WatchOne(); public Task WatchOne(CancellationToken cancelToken);
public Task Watch(CancellationToken cancelToken); public Task Watch(CancellationToken cancelToken);
public int PollPeriod { get; set; } public int PollPeriod { get; set; }

View File

@ -6,9 +6,10 @@ namespace Selector
{ {
interface IManager interface IManager
{ {
public bool IsRunning { get; }
public void Add(IWatcher watcher); public void Add(IWatcher watcher);
public bool Start(); public void Start();
public bool Stop(); public void Stop();
} }
} }

View File

@ -0,0 +1,63 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Selector
{
public class Manager: IManager, IDisposable
{
public bool IsRunning { get; private set; } = true;
private List<WatcherContext> Watchers { get; set; } = new();
public int Count => Watchers.Count;
public IEnumerable<Task> Tasks
=> Watchers
.Select(w => w.Task)
.Where(t => t is not null);
public IEnumerable<CancellationTokenSource> TokenSources
=> Watchers
.Select(w => w.TokenSource)
.Where(t => t is not null);
public void Add(IWatcher watcher)
{
var context = WatcherContext.From(watcher);
if (IsRunning) context.Start();
Watchers.Add(context);
}
public IEnumerable<WatcherContext> Running
=> Watchers.Where(w => w.IsRunning);
public void Start()
{
foreach(var watcher in Watchers)
{
watcher.Start();
}
IsRunning = true;
}
public void Stop()
{
foreach(var watcher in Watchers)
{
watcher.Stop();
}
Task.WaitAll(Tasks.ToArray());
IsRunning = false;
}
public void Dispose()
{
foreach(var watcher in Watchers)
{
watcher.Dispose();
}
}
}
}

View File

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Selector
{
public class WatcherContext: IDisposable
{
public IWatcher Watcher { get; set; }
public bool IsRunning { get; private set; }
public Task Task { get; set; }
public CancellationTokenSource TokenSource { get; set; }
public WatcherContext(IWatcher watcher)
{
Watcher = watcher;
}
public static WatcherContext From(IWatcher watcher)
{
return new(watcher);
}
public void Start()
{
if (IsRunning)
Stop();
IsRunning = true;
TokenSource = new();
Task = Watcher.Watch(TokenSource.Token);
}
public void Stop()
{
TokenSource.Cancel();
IsRunning = false;
}
private void Clear()
{
if(IsRunning
|| Task.Status == TaskStatus.Running
|| Task.Status == TaskStatus.WaitingToRun)
{
Stop();
}
Task = null;
TokenSource = null;
}
public void Dispose()
{
Stop();
Clear();
}
}
}

View File

@ -33,8 +33,10 @@ namespace Selector
PollPeriod = pollPeriod; PollPeriod = pollPeriod;
} }
public override async Task WatchOne() public override async Task WatchOne(CancellationToken token = default)
{ {
token.ThrowIfCancellationRequested();
try{ try{
var polledCurrent = await spotifyClient.GetCurrentPlayback(); var polledCurrent = await spotifyClient.GetCurrentPlayback();