More progress on IoC. Controllers are implemented

This commit is contained in:
watsonb8 2020-02-02 10:26:47 -05:00
parent 48d0ffa77d
commit 8231a18c3e
54 changed files with 521 additions and 142 deletions

View File

@ -22,4 +22,96 @@
<ItemGroup>
<ProjectReference Include="..\Aurora\Aurora.csproj" />
</ItemGroup>
<ItemGroup>
<None Update="Resources\Jidenna\The Chief\01 A Bull%27s Tale.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\04 Bambi.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\14 Bully Of The Earth.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\12 Some Kind Of Way.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\03 Trampoline.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\09 Safari.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\05 Helicopters _ Beware.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\08 The Let Out.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\10 Adaora.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\07 2 Points.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\06 Long Live The Chief.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\02 Chief Don%27t Run.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\11 Little Bit More.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Jidenna\The Chief\13 White Niggas.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\16 BDE Bonus %28Prod. By_ ID Labs%29.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\11 Play Ya Cards %28Prod By_ Chuck Inglish%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\08 All Around The World %28Prod. By_ Just Blaze%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\10 In The Air %28Prod By_ Ritz Reynolds%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\05 I%27ll Be There %28feat. Phonte%29 %28Prod. By_ Beanz %27n%27 Kornbread%29.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\03 Donald Trump %28Prod. By_ Sap%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\13 Life Ain%27t Easy %28Prod. By_ ID Labs%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\09 Down The Rabbit Hole %28Prod. By_ Blue of The Sore Losers%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\07 Wake Up %28Prod By_ Sap &amp; ID Labs%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\04 Oy Vey %28Prod By_ ID Labs%29.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\01 Best Day Ever %28Prod. By_ ID Labs%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\02 Get Up %28Prod. By_ Teddy Roxpin%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\14 Snooze %28Prod By_ ID Labs%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\12 She Said %28Prod By_ Khrysis%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\15 Keep Floatin%27 %28feat. Wiz Khalifa%29 %28Prod. By_ ID Labs%29.mp3">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="Resources\Mac Miller\Best Day Ever\06 Wear My Hat %28Prod. By_ Chuck Inglish%29.m4a">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>

View File

@ -1,9 +1,14 @@
using NUnit.Framework;
using Aurora.Proto.PartyV2;
using Aurora.Services.Server;
using Aurora.Services.Library;
using Aurora.Services.Settings;
using Aurora.test.Models.Mock;
using Grpc.Core;
using System.Threading.Tasks;
using System.Linq;
using System.IO;
using Autofac;
namespace Aurora.test.ControllerTests
{
@ -11,10 +16,35 @@ namespace Aurora.test.ControllerTests
{
private RemotePartyService.RemotePartyServiceClient _remotePartyService;
private Channel _channel;
private IContainer _container;
private IServerService _serverService;
[OneTimeSetUp]
public void SetupOneTime()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ServerService>().As<IServerService>().SingleInstance();
builder.RegisterInstance<ISettingsService>(new SettingsServiceMock()
{
Username = "Test User 1",
DefaultPort = 4005,
LibraryLocation = string.Format("{0}/Resources", Directory.GetCurrentDirectory())
}).SingleInstance();
builder.RegisterType<LibraryService>().As<ILibraryService>().SingleInstance();
_container = builder.Build();
}
[OneTimeTearDown]
public void TearDownOneTime()
{
_container.Dispose();
}
[SetUp]
public void Setup()
{
ServerService.Instance.Start("testParty", "asdf");
_serverService = _container.Resolve<IServerService>();
_serverService.Start("testParty", "asdf");
_channel = new Channel(string.Format("{0}:{1}", ServerService.GetLocalIPAddress(), 8080), ChannelCredentials.Insecure);
_remotePartyService = new RemotePartyService.RemotePartyServiceClient(_channel);
}
@ -22,8 +52,22 @@ namespace Aurora.test.ControllerTests
[TearDown]
public async Task TearDown()
{
await ServerService.Instance.Stop();
await _serverService.Stop();
await _channel.ShutdownAsync();
}
[Test]
public void TestNotEmpty()
{
ListMediaResponse resp = _remotePartyService.ListMedia(new ListMediaRequest()
{
Parent = "testParty",
PageSize = 5
});
Assert.NotNull(resp.Media);
Assert.NotZero(resp.Media.Count);
Assert.AreEqual(resp.Media.Count, 5);
}
}
}

View File

@ -1,9 +1,14 @@
using NUnit.Framework;
using Aurora.Proto.PartyV2;
using Aurora.Services.Server;
using Aurora.Services.Library;
using Aurora.Services.Settings;
using Aurora.test.Models.Mock;
using Grpc.Core;
using System.Threading.Tasks;
using System.Linq;
using System.IO;
using Autofac;
namespace Aurora.test.ControllerTests
{
@ -11,10 +16,36 @@ namespace Aurora.test.ControllerTests
{
private RemotePartyService.RemotePartyServiceClient _remotePartyService;
private Channel _channel;
private IContainer _container;
private IServerService _serverService;
[OneTimeSetUp]
public void SetupOneTime()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ServerService>().As<IServerService>().SingleInstance();
builder.RegisterInstance<ISettingsService>(new SettingsServiceMock()
{
Username = "Test User 1",
DefaultPort = 4005,
LibraryLocation = string.Format("{0}/Resource", Directory.GetCurrentDirectory())
}).SingleInstance();
builder.RegisterType<LibraryService>().As<ILibraryService>().SingleInstance();
_container = builder.Build();
}
[OneTimeTearDown]
public void TearDownOneTime()
{
_container.Dispose();
}
[SetUp]
public void Setup()
{
ServerService.Instance.Start("testParty", "asdf");
_serverService = _container.Resolve<IServerService>();
_serverService.Start("testParty", "asdf");
_channel = new Channel(string.Format("{0}:{1}", ServerService.GetLocalIPAddress(), 8080), ChannelCredentials.Insecure);
_remotePartyService = new RemotePartyService.RemotePartyServiceClient(_channel);
}
@ -22,7 +53,7 @@ namespace Aurora.test.ControllerTests
[TearDown]
public async Task TearDown()
{
await ServerService.Instance.Stop();
await _serverService.Stop();
await _channel.ShutdownAsync();
}

View File

@ -1,8 +1,13 @@
using System.Threading.Tasks;
using System.IO;
using NUnit.Framework;
using Aurora.Proto.PartyV2;
using Aurora.Services.Server;
using Aurora.Services.Library;
using Aurora.Services.Settings;
using Aurora.test.Models.Mock;
using Grpc.Core;
using Autofac;
namespace Aurora.test.ControllerTests
{
@ -10,10 +15,35 @@ namespace Aurora.test.ControllerTests
{
private RemotePartyService.RemotePartyServiceClient _remotePartyService;
private Channel _channel;
private IContainer _container;
private IServerService _serverService;
[OneTimeSetUp]
public void SetupOneTime()
{
ContainerBuilder builder = new ContainerBuilder();
builder.RegisterType<ServerService>().As<IServerService>().SingleInstance();
builder.RegisterInstance<ISettingsService>(new SettingsServiceMock()
{
Username = "Test User 1",
DefaultPort = 4005,
LibraryLocation = string.Format("{0}/Resource", Directory.GetCurrentDirectory())
}).SingleInstance();
builder.RegisterType<LibraryService>().As<ILibraryService>().SingleInstance();
_container = builder.Build();
}
[OneTimeTearDown]
public void TearDownOneTime()
{
_container.Dispose();
}
[SetUp]
public void Setup()
{
ServerService.Instance.Start("testParty", "asdf");
_serverService = _container.Resolve<IServerService>();
_serverService.Start("testParty", "asdf");
_channel = new Channel(string.Format("{0}:{1}", ServerService.GetLocalIPAddress(), 8080), ChannelCredentials.Insecure);
_remotePartyService = new RemotePartyService.RemotePartyServiceClient(_channel);
}
@ -21,7 +51,7 @@ namespace Aurora.test.ControllerTests
[TearDown]
public async Task TearDown()
{
await ServerService.Instance.Stop();
await _serverService.Stop();
await _channel.ShutdownAsync();
}

View File

@ -0,0 +1,35 @@
using Aurora.Services.Settings;
using Plugin.Settings.Abstractions;
namespace Aurora.test.Models.Mock
{
public class SettingsServiceMock : ISettingsService
{
public SettingsServiceMock()
{
}
public ISettings AppSettings { get; set; }
/// <summary>
/// The user's username. This is persisted.
/// </summary>
/// <value></value>
public string Username { get; set; }
/// <summary>
/// The default port to use. This is persisted.
/// </summary>
/// <value></value>
public int DefaultPort { get; set; }
/// <summary>
/// The current sessions clientId. This is assigned by the server. This is not persisted.
/// </summary>
/// <value></value>
public string ClientId { get; set; }
public string LibraryLocation { get; set; }
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -12,6 +12,7 @@ using LibVLCSharp.Shared;
using Xamarin.Forms;
using Aurora.Services.Player;
using Aurora.Services.Settings;
using Aurora.Services.Library;
namespace Aurora
{
@ -29,6 +30,7 @@ namespace Aurora
_builder.RegisterType<PlayerService>().As<IPlayer>().SingleInstance();
_builder.RegisterType<SettingsService>().As<ISettingsService>().SingleInstance();
_builder.RegisterType<ClientService>().As<IClientService>().SingleInstance();
_builder.RegisterType<LibraryService>().As<ILibraryService>().SingleInstance();
_builder.RegisterType<MainView>().SingleInstance();
_builder.RegisterType<AlbumsViewModel>();
_builder.RegisterType<ArtistsViewModel>();

View File

@ -22,6 +22,14 @@
<Entry
Text="{Binding Port}"/>
</StackLayout>
<StackLayout
Orientation="Horizontal">
<Label
VerticalOptions="Center"
Text="Path to Library"/>
<Entry
Text="{Binding LibraryPath}"/>
</StackLayout>
</StackLayout>
</ContentView.Content>
</ContentView>

View File

@ -32,5 +32,15 @@ namespace Aurora.Design.Views.Profile
OnPropertyChanged("Port");
}
}
public string LibraryPath
{
get { return this._settingsService.LibraryLocation; }
set
{
this._settingsService.LibraryLocation = value;
OnPropertyChanged("LibraryPath");
}
}
}
}

View File

@ -1,6 +1,6 @@
using System.Collections.ObjectModel;
using Aurora.Models.Media;
using Aurora.Services;
using Aurora.Services.Library;
using Xamarin.Forms;
namespace Aurora.Design.Views.Songs
@ -10,15 +10,18 @@ namespace Aurora.Design.Views.Songs
#region Fields
private ObservableCollection<BaseMedia> _songsList;
private BaseMedia _selectedSong;
private ILibraryService _libraryService;
#endregion Fields
#region Constructor
public SongsViewModel()
public SongsViewModel(ILibraryService libraryService)
{
_songsList = new ObservableCollection<BaseMedia>();
DoubleClickCommand = new Command(OnDoubleClickExecute, OnDoubleClickCanExecute);
this._libraryService = libraryService;
Initialize();
}
@ -45,7 +48,7 @@ namespace Aurora.Design.Views.Songs
public void Initialize()
{
SongsList = LibraryService.Instance.GetLibrary();
SongsList = this._libraryService.GetLibrary();
}
#endregion Methods

View File

@ -10,6 +10,7 @@ namespace Aurora.Models.Media
public BaseMedia()
{
//TODO need to make sure this is unique
Id = Guid.NewGuid().ToString();
}

View File

@ -239,8 +239,6 @@ message MemberDeletedEvent {
}
message EventSubscription {
//Resource name of the event
string name = 1;
EventType type = 2;
}
@ -253,7 +251,6 @@ message ListEventSubscriptionsRequest {
message ListEventSubscriptionsResponse {
repeated EventSubscription subscriptions = 1;
string nextPageToken = 3;
}
message CreateEventSubscriptionRequest {
@ -264,7 +261,8 @@ message CreateEventSubscriptionRequest {
message DeleteEventSubscriptionRequest {
//Resource name of the subscription to delete
string name = 1;
string parent = 1;
EventType type = 2;
}
message DeleteAllEventSubscriptionsRequest {

View File

@ -6,8 +6,9 @@ using Aurora.Utils;
using Aurora.Proto.Party;
using Aurora.Proto.Events;
using Aurora.Services.EventManager;
using Aurora.Services;
using Aurora.Models.Media;
using Aurora.Services.Library;
using Autofac;
namespace Aurora.RemoteImpl
{
@ -90,49 +91,56 @@ namespace Aurora.RemoteImpl
public override Task<QueueResponse> GetQueue(Proto.General.Empty empty, Grpc.Core.ServerCallContext context)
{
QueueResponse mediaList = new QueueResponse();
//This will change as queuing operation gets solidified
//Simply return the hosts library
ObservableCollection<BaseMedia> queue = LibraryService.Instance.GetLibrary();
QueueResponse mediaList = new QueueResponse();
foreach (BaseMedia media in queue)
using (var scope = App.Container.BeginLifetimeScope())
{
AudioMetadata metadata = new AudioMetadata();
try
ILibraryService library = scope.Resolve<ILibraryService>();
ObservableCollection<BaseMedia> queue = library.GetLibrary();
foreach (BaseMedia media in queue)
{
if (media.Metadata is AudioMetadata)
AudioMetadata metadata = new AudioMetadata();
try
{
metadata = media.Metadata as AudioMetadata;
if (media.Metadata is AudioMetadata)
{
metadata = media.Metadata as AudioMetadata;
RemoteMediaData data = new RemoteMediaData();
data.Id = media.Id;
if (metadata.Title != null)
{
data.Title = metadata.Title;
}
if (metadata.Artist != null)
{
data.Artist = metadata.Artist;
}
if (metadata.Album != null)
{
data.Album = metadata.Album;
}
if (metadata.Duration != null)
{
data.Duration = metadata.Duration;
}
RemoteMediaData data = new RemoteMediaData();
data.Id = media.Id;
if (metadata.Title != null)
{
data.Title = metadata.Title;
}
if (metadata.Artist != null)
{
data.Artist = metadata.Artist;
}
if (metadata.Album != null)
{
data.Album = metadata.Album;
}
if (metadata.Duration != null)
{
data.Duration = metadata.Duration;
}
mediaList.MediaList.Add(data);
mediaList.MediaList.Add(data);
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Error preparing queue: {0}", ex.Message));
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Error preparing queue: {0}", ex.Message));
}
}
return Task.FromResult(mediaList);
}

View File

@ -1,11 +1,10 @@
using System;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Generic;
using Aurora.Services;
using Aurora.Proto.Playback;
using Aurora.Proto.General;
using Aurora.Models.Media;
using Aurora.Services.Library;
using Autofac;
namespace Aurora.RemoteImpl
{
@ -15,38 +14,44 @@ namespace Aurora.RemoteImpl
Grpc.Core.IServerStreamWriter<Chunk> responseStream,
Grpc.Core.ServerCallContext context)
{
BaseMedia originalSong = LibraryService.Instance.GetSong(request.Id);
if (!(originalSong is LocalAudio))
using (var scope = App.Container.BeginLifetimeScope())
{
return;
}
ILibraryService library = scope.Resolve<ILibraryService>();
//Copy media object to not interfere with other threads
LocalAudio songCopy = new LocalAudio((LocalAudio)originalSong);
try
{
//Load only if not already loaded. (Multiple clients may be requesting media)
if (!songCopy.IsLoaded)
BaseMedia originalSong = library.GetSong(request.Id);
if (!(originalSong is LocalAudio))
{
await songCopy.Load();
return;
}
//Send stream
Console.WriteLine("Begin sending file");
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = songCopy.DataStream.Read(buffer, 0, buffer.Length)) > 0)
//Copy media object to not interfere with other threads
LocalAudio songCopy = new LocalAudio((LocalAudio)originalSong);
try
{
Google.Protobuf.ByteString bufferByteString = Google.Protobuf.ByteString.CopyFrom(buffer);
await responseStream.WriteAsync(new Chunk { Content = bufferByteString });
//Load only if not already loaded. (Multiple clients may be requesting media)
if (!songCopy.IsLoaded)
{
await songCopy.Load();
}
//Send stream
Console.WriteLine("Begin sending file");
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = songCopy.DataStream.Read(buffer, 0, buffer.Length)) > 0)
{
Google.Protobuf.ByteString bufferByteString = Google.Protobuf.ByteString.CopyFrom(buffer);
await responseStream.WriteAsync(new Chunk { Content = bufferByteString });
}
Console.WriteLine("Done sending file");
}
catch (Exception ex)
{
Console.WriteLine("Exception caught while sending audio file: " + ex.Message);
}
Console.WriteLine("Done sending file");
}
catch (Exception ex)
{
Console.WriteLine("Exception caught while sending audio file: " + ex.Message);
}
}
}
}

View File

@ -0,0 +1,12 @@
using System.Collections.ObjectModel;
using Aurora.Models.Media;
namespace Aurora.Services.Library
{
public interface ILibraryService
{
ObservableCollection<BaseMedia> GetLibrary();
BaseMedia GetSong(string Id);
}
}

View File

@ -3,22 +3,24 @@ using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using Aurora.Models.Media;
using Aurora.Services.Settings;
using Aurora.Utils;
namespace Aurora.Services
namespace Aurora.Services.Library
{
public class LibraryService : BaseService<LibraryService>
public class LibraryService : ILibraryService
{
#region Fields
private string _pathName = "/Users/brandonwatson/Music/iTunes/iTunes Media/Music";
private string _pathName;
private string _extensions = ".wav,.mp3,.aiff,.flac,.m4a,.m4b,.wma";
private Dictionary<string, BaseMedia> _library;
#endregion Fields
public LibraryService()
public LibraryService(ISettingsService settingsService)
{
_library = new Dictionary<string, BaseMedia>();
this._pathName = settingsService.LibraryLocation;
LoadLibrary();
}

View File

@ -9,7 +9,7 @@ using LibVLCSharp.Shared;
namespace Aurora.Services.Player
{
public class PlayerService : BaseService<PlayerService>, IPlayer
public class PlayerService : IPlayer
{
private const long _ticksPerMillisecond = 10000;
private BaseMedia _currentMedia;

View File

@ -1,22 +1,29 @@
using System;
using System.Threading.Tasks;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using Aurora.Proto.PartyV2;
using Aurora.Services.Library;
using Aurora.Models.Media;
using Autofac;
namespace Aurora.Services.Server.Controllers
{
public partial class RemotePartyController : RemotePartyService.RemotePartyServiceBase
{
private ILibraryService _libraryService;
/// <summary>
/// Constructor for partial class
/// </summary>
public RemotePartyController(string partyName, string description)
public RemotePartyController(string partyName, string description, ILibraryService libraryService)
{
this._startDateTime = DateTime.UtcNow;
this._displayName = partyName;
this._description = description;
this._memberList = new SortedList<string, Member>();
this._mediaList = new SortedList<string, Models.Media.BaseMedia>();
this._mediaList = new SortedList<string, Media>();
_libraryService = libraryService;
string userName = "testUser";
@ -32,7 +39,47 @@ namespace Aurora.Services.Server.Controllers
this._memberList.Add(_hostMember.Name, _hostMember);
//Add media from library
//This will change as queuing operation gets solidified
//Simply return the hosts library
ObservableCollection<BaseMedia> queue = _libraryService.GetLibrary();
foreach (BaseMedia media in queue)
{
AudioMetadata metadata = new AudioMetadata();
try
{
if (media.Metadata is AudioMetadata)
{
metadata = media.Metadata as AudioMetadata;
Media data = new Media();
data.Name = media.Id;
if (metadata.Title != null)
{
data.Title = metadata.Title;
}
if (metadata.Artist != null)
{
data.Artist = metadata.Artist;
}
if (metadata.Album != null)
{
data.Album = metadata.Album;
}
if (metadata.Duration != null)
{
data.Duration = metadata.Duration;
}
_mediaList.Add(data.Name, data);
}
}
catch (Exception ex)
{
Console.WriteLine(string.Format("Error preparing queue: {0}", ex.Message));
}
}
}
}
}

View File

@ -1,6 +1,8 @@
using System;
using System.Threading.Tasks;
using System.Threading;
using Aurora.Proto.PartyV2;
using Aurora.Utils;
namespace Aurora.Services.Server.Controllers
{
@ -8,7 +10,26 @@ namespace Aurora.Services.Server.Controllers
{
public override Task GetEvents(GetEventsRequest request, Grpc.Core.IServerStreamWriter<BaseEvent> responseStream, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
string peerId = Misc.Combine(new string[] { context.Peer, request.Parent });
Console.WriteLine(string.Format("SERVER - Events request received from peer: {0}", peerId));
AutoResetEvent are = new AutoResetEvent(false);
Action<BaseEvent> callback = (BaseEvent bEvent) =>
{
Console.WriteLine(string.Format("SERVER - Event fired for peer: {0}", peerId));
//TODO need to remove callback if stream no longer exists IE. Client crashed or stopped
responseStream.WriteAsync(bEvent);
};
Action cancelled = () =>
{
are.Set();
};
this._eventManager.AddEventHandler(callback, cancelled, Misc.Combine(new string[] { context.Peer, request.Parent }));
are.WaitOne();
return Task.FromResult<object>(null);
}
}
}

View File

@ -2,6 +2,7 @@ using System;
using System.Threading.Tasks;
using Aurora.Proto.PartyV2;
using Aurora.Proto.General;
using Aurora.Utils;
namespace Aurora.Services.Server.Controllers
{
@ -14,17 +15,24 @@ namespace Aurora.Services.Server.Controllers
public override Task<EventSubscription> CreateEventSubscription(CreateEventSubscriptionRequest request, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
Console.WriteLine(string.Format("SERVER - Subscription from client with id: {0}", request.Parent));
this._eventManager.AddSubscription(Misc.Combine(new string[] { context.Peer, request.Parent }), request.EventSubscription.Type);
return Task.FromResult(request.EventSubscription);
}
public override Task<Empty> DeleteEventSubscription(DeleteEventSubscriptionRequest request, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
this._eventManager.RemoveSubscription(Misc.Combine(new string[] { context.Peer, request.Parent }), request.Type);
return Task.FromResult(new Empty());
}
public override Task<Empty> DeleteAllEventSubscriptions(DeleteAllEventSubscriptionsRequest request, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
this._eventManager.RemoveAllSubscriptions(Misc.Combine(new string[] { context.Peer, request.Parent }));
return Task.FromResult(new Empty());
}
}
}

View File

@ -4,6 +4,7 @@ using System.Collections.Generic;
using Aurora.Proto.PartyV2;
using Aurora.Models.Media;
using Aurora.Proto.General;
using Aurora.Services.Library;
using Aurora.Services.Player;
using Autofac;
@ -11,7 +12,7 @@ namespace Aurora.Services.Server.Controllers
{
public partial class RemotePartyController : RemotePartyService.RemotePartyServiceBase
{
private SortedList<string, BaseMedia> _mediaList;
private SortedList<string, Media> _mediaList;
public override Task<ListMediaResponse> ListMedia(ListMediaRequest request, Grpc.Core.ServerCallContext context)
{
@ -31,22 +32,8 @@ namespace Aurora.Services.Server.Controllers
}
//Gather page
List<BaseMedia> baseMedia = new List<BaseMedia>(_mediaList.Values);
foreach (BaseMedia media in baseMedia)
{
if (media.Metadata is AudioMetadata)
{
AudioMetadata meta = media.Metadata as AudioMetadata;
resp.Media.Add(new Media()
{
Name = media.Id,
Title = meta.Title,
Album = meta.Album,
Artist = meta.Artist,
Duration = meta.Duration
});
}
}
List<Media> mediaList = new List<Media>(_mediaList.Values);
resp.Media.AddRange(mediaList.GetRange(startIdx, pageSize));
resp.NextPageToken = resp.Media[resp.Media.Count - 1].Name;
return Task.FromResult(resp);
@ -54,24 +41,14 @@ namespace Aurora.Services.Server.Controllers
public override Task<Media> GetMedia(GetMediaRequest request, Grpc.Core.ServerCallContext context)
{
_mediaList.TryGetValue(request.Name, out BaseMedia baseMedia);
_mediaList.TryGetValue(request.Name, out Media baseMedia);
if (baseMedia == null)
{
throw new KeyNotFoundException();
}
Media media = new Media();
if (baseMedia.Metadata != null && baseMedia.Metadata is AudioMetadata)
{
AudioMetadata metadata = baseMedia.Metadata as AudioMetadata;
media.Name = baseMedia.Id;
media.Title = metadata.Title;
media.Artist = metadata.Artist;
media.Album = metadata.Album;
}
return Task.FromResult(media);
return Task.FromResult(baseMedia);
}
public override Task<Media> CreateMedia(CreateMediaRequest request, Grpc.Core.ServerCallContext context)
@ -86,37 +63,43 @@ namespace Aurora.Services.Server.Controllers
public override async Task StreamMedia(StreamMediaRequest request, Grpc.Core.IServerStreamWriter<Proto.General.Chunk> responseStream, Grpc.Core.ServerCallContext context)
{
BaseMedia originalSong = LibraryService.Instance.GetSong(request.Name);
if (!(originalSong is LocalAudio))
using (var scope = App.Container.BeginLifetimeScope())
{
return;
}
ILibraryService library = scope.Resolve<ILibraryService>();
//Copy media object to not interfere with other threads
LocalAudio songCopy = new LocalAudio((LocalAudio)originalSong);
try
{
//Load only if not already loaded. (Multiple clients may be requesting media)
if (!songCopy.IsLoaded)
BaseMedia originalSong = library.GetSong(request.Name);
if (!(originalSong is LocalAudio))
{
await songCopy.Load();
return;
}
//Send stream
Console.WriteLine("Begin sending file");
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = songCopy.DataStream.Read(buffer, 0, buffer.Length)) > 0)
//Copy media object to not interfere with other threads
LocalAudio songCopy = new LocalAudio((LocalAudio)originalSong);
try
{
Google.Protobuf.ByteString bufferByteString = Google.Protobuf.ByteString.CopyFrom(buffer);
await responseStream.WriteAsync(new Chunk { Content = bufferByteString });
//Load only if not already loaded. (Multiple clients may be requesting media)
if (!songCopy.IsLoaded)
{
await songCopy.Load();
}
//Send stream
Console.WriteLine("Begin sending file");
byte[] buffer = new byte[2048]; // read in chunks of 2KB
int bytesRead;
while ((bytesRead = songCopy.DataStream.Read(buffer, 0, buffer.Length)) > 0)
{
Google.Protobuf.ByteString bufferByteString = Google.Protobuf.ByteString.CopyFrom(buffer);
await responseStream.WriteAsync(new Chunk { Content = bufferByteString });
}
Console.WriteLine("Done sending file");
}
Console.WriteLine("Done sending file");
}
catch (Exception ex)
{
Console.WriteLine("Exception caught while sending audio file: " + ex.Message);
catch (Exception ex)
{
Console.WriteLine("Exception caught while sending audio file: " + ex.Message);
}
}
}

View File

@ -0,0 +1,27 @@
using System.Threading.Tasks;
namespace Aurora.Services.Server
{
public interface IServerService
{
int Port { get; }
string Hostname { get; }
bool Initialized { get; }
/// <summary>
/// Start Server
/// </summary>
void Start(string partyName, string description);
/// <summary>
/// Shutdown server async.
/// </summary>
/// <returns>Task</returns>
Task Stop();
Task Reset();
}
}

View File

@ -4,16 +4,18 @@ using System.Net;
using System.Net.Sockets;
using Grpc.Core;
using Aurora.Services.Server.Controllers;
using Aurora.Services.Library;
using Aurora.Proto.PartyV2;
namespace Aurora.Services.Server
{
public class ServerService : BaseService<ServerService>
public class ServerService : IServerService
{
private int _port = 8080;
private string _hostname;
private Grpc.Core.Server _server;
private ILibraryService _libraryService;
//Implementation class declarations
private RemotePartyController _remotePartyController;
@ -21,10 +23,10 @@ namespace Aurora.Services.Server
/// <summary>
/// Constructor. Registers GRPC service implementations.
/// </summary>
public ServerService()
public ServerService(ILibraryService libraryService)
{
string host = GetLocalIPAddress();
this._libraryService = libraryService;
if (string.IsNullOrWhiteSpace(host))
{
throw new Exception("This device must have a valid IP address");
@ -69,7 +71,7 @@ namespace Aurora.Services.Server
};
//Construct implementations
_remotePartyController = new RemotePartyController(partyName, description);
_remotePartyController = new RemotePartyController(partyName, description, _libraryService);
// Register grpc RemoteService with singleton server service
RegisterService(RemotePartyService.BindService(_remotePartyController));

View File

@ -23,5 +23,7 @@ namespace Aurora.Services.Settings
/// </summary>
/// <value></value>
string ClientId { get; set; }
string LibraryLocation { get; set; }
}
}

View File

@ -11,6 +11,8 @@ namespace Aurora.Services.Settings
private string _usernameKey = "username";
private string _defaultPortKey = "port";
private string _libraryLocationKey = "libraryLocation";
public SettingsService()
{
}
@ -55,6 +57,12 @@ namespace Aurora.Services.Settings
set { AppSettings.AddOrUpdateValue(_defaultPortKey, value); }
}
public string LibraryLocation
{
get { return AppSettings.GetValueOrDefault(_libraryLocationKey, "~/Music"); }
set { AppSettings.AddOrUpdateValue(_libraryLocationKey, value); }
}
/// <summary>
/// The current sessions clientId. This is assigned by the server. This is not persisted.
/// </summary>