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

@ -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>