Adding dependency injection

This commit is contained in:
watsonb8 2020-01-31 20:41:45 -05:00
parent f8ad2f459e
commit 48d0ffa77d
27 changed files with 550 additions and 114 deletions

View File

@ -150,7 +150,7 @@
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.2\lib\netstandard2.0\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.1.1.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="System.Linq.Async">
<HintPath>..\packages\System.Linq.Async.4.0.0\lib\net461\System.Linq.Async.dll</HintPath>
@ -164,6 +164,10 @@
<Reference Include="CarouselView.FormsPlugin.Abstractions">
<HintPath>..\packages\CarouselView.FormsPlugin.5.2.0\lib\netstandard2.0\CarouselView.FormsPlugin.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Autofac">
<HintPath>..\packages\Autofac.5.0.0\lib\net461\Autofac.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
</ItemGroup>
<ItemGroup>
<EmbeddedResource Include="gtk-gui\gui.stetic">

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Autofac" version="5.0.0" targetFramework="net47" />
<package id="CarouselView.FormsPlugin" version="5.2.0" targetFramework="net47" />
<package id="DLToolkit.Forms.Controls.FlowListView" version="2.0.11" targetFramework="net47" />
<package id="Google.Protobuf" version="3.10.1" targetFramework="net47" />
@ -13,7 +14,7 @@
<package id="LibVLCSharp.GTK" version="3.3.1" targetFramework="net47" />
<package id="Microsoft.Bcl" version="1.1.10" targetFramework="net47" />
<package id="Microsoft.Bcl.Async" version="1.0.168" targetFramework="net47" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.0.0" targetFramework="net47" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="1.1.0" targetFramework="net47" />
<package id="Microsoft.Bcl.Build" version="1.0.21" targetFramework="net47" />
<package id="OpenTK" version="3.1.0" targetFramework="net47" />
<package id="OpenTK.GLControl" version="3.0.1" targetFramework="net47" />

View File

@ -13,6 +13,7 @@
<PrivateAssets>all</PrivateAssets>
</PackageReference>
<PackageReference Include="Grpc" Version="2.26.0" />
<PackageReference Include="Autofac" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Protobuf Remove="..\Aurora\Proto\general.proto" />

View File

@ -0,0 +1,29 @@
using NUnit.Framework;
using Aurora.Proto.PartyV2;
using Aurora.Services.Server;
using Grpc.Core;
using System.Threading.Tasks;
using System.Linq;
namespace Aurora.test.ControllerTests
{
public class MediaControllerTests
{
private RemotePartyService.RemotePartyServiceClient _remotePartyService;
private Channel _channel;
[SetUp]
public void Setup()
{
ServerService.Instance.Start("testParty", "asdf");
_channel = new Channel(string.Format("{0}:{1}", ServerService.GetLocalIPAddress(), 8080), ChannelCredentials.Insecure);
_remotePartyService = new RemotePartyService.RemotePartyServiceClient(_channel);
}
[TearDown]
public async Task TearDown()
{
await ServerService.Instance.Stop();
await _channel.ShutdownAsync();
}
}
}

View File

@ -139,5 +139,50 @@ namespace Aurora.test.ControllerTests
Assert.AreEqual(resp.Members.Count, 5);
Assert.False(resp.Members.Any(member => member.UserName == "Ke$sha"));
}
static object[] PagingCases =
{
new object[] {"Tupac", "Aubrey Grahm", "Beyonce Knowls", "Ke$ha", "A$ap Ferg", "asdf", "sdfa", "dfas", "fasd"},
};
[Test]
[TestCaseSource("PagingCases")]
public void MemberPagingTest(object[] members)
{
foreach (string name in members)
{
Member member = _remotePartyService.CreateMember(new CreateMemberRequest()
{
Parent = "party1",
Member = new Member()
{
UserName = name
}
});
Assert.NotNull(member);
}
//List members
ListMembersResponse resp = _remotePartyService.ListMembers(new ListMembersRequest()
{
Parent = "party1",
PageSize = 2,
});
string nextPageToken = resp.NextPageToken;
Assert.AreEqual(resp.Members.Count, 2);
//List members
resp = _remotePartyService.ListMembers(new ListMembersRequest()
{
Parent = "party1",
PageSize = 2,
PageToken = nextPageToken,
});
Assert.AreEqual(resp.Members.Count, 2);
}
}
}

View File

@ -1,19 +1,51 @@
using System;
using Aurora.Design.Views.Main;
using Aurora.Design.Views.Albums;
using Aurora.Design.Views.Artists;
using Aurora.Design.Views.Party;
using Aurora.Design.Views.Profile;
using Aurora.Design.Views.Songs;
using Aurora.Design.Views.Stations;
using Aurora.Services.ClientService;
using Autofac;
using LibVLCSharp.Shared;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Aurora.Services.Player;
using Aurora.Services.Settings;
namespace Aurora
{
public partial class App : Application
{
private static IContainer _container;
public App()
{
InitializeComponent();
Core.Initialize();
MainPage = new MainView();
//Register DI
ContainerBuilder _builder = new ContainerBuilder();
// _builder.RegisterInstance<IPlayer>(new PlayerService()).SingleInstance();
_builder.RegisterType<PlayerService>().As<IPlayer>().SingleInstance();
_builder.RegisterType<SettingsService>().As<ISettingsService>().SingleInstance();
_builder.RegisterType<ClientService>().As<IClientService>().SingleInstance();
_builder.RegisterType<MainView>().SingleInstance();
_builder.RegisterType<AlbumsViewModel>();
_builder.RegisterType<ArtistsViewModel>();
_builder.RegisterType<PartyViewModel>();
_builder.RegisterType<ProfileViewModel>();
_builder.RegisterType<SongsViewModel>();
_builder.RegisterType<StationsViewModel>();
// _builder.RegisterInstance<ISettingsService>(new SettingsService()).SingleInstance();
_container = _builder.Build();
MainPage = _container.Resolve<MainView>();
}
public static IContainer Container
{
get { return _container; }
}
protected override void OnStart()

View File

@ -23,6 +23,7 @@
<PackageReference Include="Sharpnado.Forms.HorizontalListView" Version="1.3.0" />
<PackageReference Include="DLToolkit.Forms.Controls.FlowListView" Version="2.0.11" />
<PackageReference Include="CarouselView.FormsPlugin" Version="5.2.0" />
<PackageReference Include="Autofac" Version="5.0.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Design\" />

View File

@ -9,8 +9,8 @@ using Xamarin.Forms;
using Xamarin.Forms.Xaml;
using Aurora.Models.Media;
using Aurora.Design.Components.MediaPlayer;
using Aurora.Services.PlayerService;
using System.Threading;
using Aurora.Services.Player;
using Autofac;
namespace Aurora.Design.Views.Main
{
@ -38,10 +38,10 @@ namespace Aurora.Design.Views.Main
private Dictionary<int, BaseViewModel> _viewModels;
private BaseViewModel _lastViewModel;
private Player _playerComponent;
private PlayerService _playerService;
private IPlayer _playerService;
private ContentPresenter _viewContent;
public MainView()
public MainView(IPlayer player)
{
InitializeComponent();
BindingContext = new MainViewModel();
@ -50,7 +50,7 @@ namespace Aurora.Design.Views.Main
_playerComponent = Player;
_viewContent = (ContentPresenter)Content.FindByName("ViewContent");
_playerService = PlayerService.Instance;
_playerService = player;
MasterPage.ListView.ItemSelected += OnNavItemSelected;
@ -89,7 +89,7 @@ namespace Aurora.Design.Views.Main
}
//Instantiate new view model
vm = (BaseViewModel)Activator.CreateInstance(item.TargetViewModelType);
vm = (BaseViewModel)App.Container.Resolve(item.TargetViewModelType); //Activator.CreateInstance(item.TargetViewModelType);
_viewModels.Add(item.Id, vm);
}
@ -135,7 +135,7 @@ namespace Aurora.Design.Views.Main
else
{
//Instantiate new view model
vm = (BaseViewModel)Activator.CreateInstance(firstNavItem.TargetViewModelType);
vm = (BaseViewModel)App.Container.Resolve(firstNavItem.TargetViewModelType); //(BaseViewModel)Activator.CreateInstance(firstNavItem.TargetViewModelType);
_viewModels.Add(firstNavItem.Id, vm);
}

View File

@ -9,10 +9,11 @@ using Aurora.Proto.Party;
using Aurora.Proto.Events;
using Aurora.Services.ClientService;
using Aurora.Services.ClientService.Events;
using Aurora.Services.PlayerService;
using Aurora.Services.Player;
using Aurora.Services.EventManager;
using Aurora.Models.Media;
using Aurora.Design.Views.Party.NewPartyDialog;
using Aurora.Services.Settings;
namespace Aurora.Design.Views.Party
{
@ -32,22 +33,25 @@ namespace Aurora.Design.Views.Party
private ObservableCollection<PartyMember> _members;
private ObservableCollection<BaseMedia> _queue;
private BaseMedia _selectedMedia;
private ClientService _client;
private IClientService _client;
private ISettingsService _settingsService;
private int _selectedTabIndex;
public PartyViewModel()
public PartyViewModel(ISettingsService settingsService, IClientService clientService)
{
_members = new ObservableCollection<PartyMember>();
_queue = new ObservableCollection<BaseMedia>();
this._settingsService = settingsService;
SetState(PartyState.SelectingHost);
PlayCommand = new Command(OnDoubleClickCommandExecute, CanDoubleClickCommandExecute);
LeavePartyCommand = new Command(OnLeavePartyCommandExecute, CanLeavePartyCommandExecute);
_client = ClientService.Instance;
_client = clientService;
_client.OnMediaPaused += this.OnRemoteMediaPaused;
_client.OnMediaResumed += this.OnRemoteMediaResumed;
@ -245,7 +249,7 @@ namespace Aurora.Design.Views.Party
private async void OnJoinCommandExecute()
{
SetState(PartyState.Connecting);
_client.Start(_hostname, SettingsService.Instance.DefaultPort.ToString());
_client.Start(_hostname, this._settingsService.DefaultPort.ToString());
await JoinParty(false);
//TODO add cancellation token
@ -272,7 +276,7 @@ namespace Aurora.Design.Views.Party
ServerService.Instance.Start();
string localHost = ServerService.GetLocalIPAddress();
_client.IsHost = true;
_client.Start(localHost, SettingsService.Instance.DefaultPort.ToString());
_client.Start(localHost, this._settingsService.DefaultPort.ToString());
await JoinParty(true);
@ -387,10 +391,10 @@ namespace Aurora.Design.Views.Party
{
JoinPartyResponse resp = await _client.RemotePartyClient.JoinPartyAsync(new JoinPartyRequest
{
UserName = SettingsService.Instance.Username,
UserName = this._settingsService.Username,
});
SettingsService.Instance.ClientId = resp.ClientId;
this._settingsService.ClientId = resp.ClientId;
RefreshMembers();
@ -447,13 +451,13 @@ namespace Aurora.Design.Views.Party
req.EventTypes.Add(EventType.PartyMemberLeft);
req.EventTypes.Add(EventType.MediaPlaying);
req.EventTypes.Add(EventType.MediaStopped);
if (!string.IsNullOrWhiteSpace(SettingsService.Instance.ClientId))
if (!string.IsNullOrWhiteSpace(this._settingsService.ClientId))
{
req.ClientId = SettingsService.Instance.ClientId;
req.ClientId = this._settingsService.ClientId;
}
Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", SettingsService.Instance.ClientId));
Console.WriteLine(string.Format("CLIENT {0} - SubscribeToEvents called from client with id", this._settingsService.ClientId));
await _client.RemoteEventClient.SubscribeToEventsAsync(req);
}
private async Task UnsubscribeFromEvents()

View File

@ -1,32 +1,34 @@
using System;
using Aurora.Services;
using Aurora.Services.Settings;
namespace Aurora.Design.Views.Profile
{
public class ProfileViewModel : BaseViewModel
{
private ISettingsService _settingsService;
public ProfileViewModel()
public ProfileViewModel(ISettingsService settingsService)
{
this._settingsService = settingsService;
}
public string Username
{
get { return SettingsService.Instance.Username; }
get { return this._settingsService.Username; }
set
{
SettingsService.Instance.Username = value;
this._settingsService.Username = value;
OnPropertyChanged("Username");
}
}
public string Port
{
get { return SettingsService.Instance.DefaultPort.ToString(); }
get { return this._settingsService.DefaultPort.ToString(); }
set
{
Int32.TryParse(value, out int portNum);
SettingsService.Instance.DefaultPort = portNum;
this._settingsService.DefaultPort = portNum;
OnPropertyChanged("Port");
}
}

View File

@ -44,7 +44,13 @@ service RemotePartyService {
rpc ListMedia(ListMediaRequest) returns (ListMediaResponse);
//Get
rpc GetMedia(GetMediaRequest) returns (RemoteMedia);
rpc GetMedia(GetMediaRequest) returns (Media);
//Create
rpc CreateMedia(CreateMediaRequest) returns (Media);
//Delete
rpc DeleteMedia(DeleteMediaRequest) returns (Aurora.Proto.General.Empty) {};
//CUSTOM: Stream
rpc StreamMedia(StreamMediaRequest) returns (stream Aurora.Proto.General.Chunk) {};
@ -97,7 +103,10 @@ message Member {
//Resource name of the party member to be returned (Added by server)
string name = 1;
string userName = 2;
//Added by server
string ipAddress = 3;
//Added by server
google.protobuf.Timestamp addedOn = 4;
}
@ -134,7 +143,7 @@ message DeleteMemberRequest {
string name = 1;
}
message RemoteMedia {
message Media {
//Resource name of the remote media object
string name = 1;
string title = 2;
@ -151,7 +160,7 @@ message ListMediaRequest {
}
message ListMediaResponse {
repeated RemoteMedia media = 1;
repeated Media media = 1;
string nextPageToken = 3;
}
@ -160,6 +169,17 @@ message GetMediaRequest {
string name = 1;
}
message CreateMediaRequest {
//Resource name of the parent collection of the member to be created (The party)
string parent = 1;
Media media = 2;
}
message DeleteMediaRequest {
//Resource name of the member to be deleted
string name = 1;
}
message StreamMediaRequest {
//Resource name of the media requested
string name = 1;
@ -199,7 +219,7 @@ message BaseEvent {
}
message NewMediaPlayingEvent {
RemoteMedia media = 1;
Media media = 1;
}
message MediaResumedEvent {

View File

@ -2,7 +2,9 @@ using System;
using System.Threading.Tasks;
using Aurora.Proto.Sync;
using Aurora.Proto.General;
using Aurora.Services.PlayerService;
using Aurora.Services.Player;
using Aurora;
using Autofac;
namespace Aurora.RemoteImpl
{
@ -19,31 +21,36 @@ namespace Aurora.RemoteImpl
Grpc.Core.IServerStreamWriter<Sync> responseStream,
Grpc.Core.ServerCallContext context)
{
bool continueSync = true;
string currentId = PlayerService.Instance.CurrentMedia.Id;
MediaChangedEventHandler mediaChanged = (sender, e) =>
using (var scope = App.Container.BeginLifetimeScope())
{
if (e.NewId != currentId)
IPlayer player = scope.Resolve<IPlayer>();
bool continueSync = true;
string currentId = player.CurrentMedia.Id;
MediaChangedEventHandler mediaChanged = (sender, e) =>
{
continueSync = false;
}
};
PlayerService.Instance.MediaChanged += mediaChanged;
while (continueSync)
{
float length = PlayerService.Instance.CurrentMediaLength;
Sync sync = new Sync()
{
TrackPosition = PlayerService.Instance.CurrentMediaPosition,
ServerTimeTicks = Utils.TimeUtils.GetNetworkTime().DateTime.Ticks
if (e.NewId != currentId)
{
continueSync = false;
}
};
await responseStream.WriteAsync(sync);
Console.WriteLine("Sent Sync");
await Task.Delay(5000);
player.MediaChanged += mediaChanged;
while (continueSync)
{
float length = player.CurrentMediaLength;
Sync sync = new Sync()
{
TrackPosition = player.CurrentMediaPosition,
ServerTimeTicks = Utils.TimeUtils.GetNetworkTime().DateTime.Ticks
};
await responseStream.WriteAsync(sync);
Console.WriteLine("Sent Sync");
await Task.Delay(5000);
}
}
}
}
}

View File

@ -8,11 +8,12 @@ using Aurora.Proto.Playback;
using Aurora.Proto.Sync;
using Aurora.Services.ClientService.Events;
using System.Collections.Generic;
using Aurora.Services.Settings;
namespace Aurora.Services.ClientService
{
public class ClientService : BaseService<ClientService>
public class ClientService : IClientService
{
private RemotePartyService.RemotePartyServiceClient _remotePartyClient;
private RemoteEventService.RemoteEventServiceClient _remoteEventsClient;
@ -20,17 +21,19 @@ namespace Aurora.Services.ClientService
private RemoteSyncService.RemoteSyncServiceClient _remoteSyncClient;
private Channel _channel;
CancellationTokenSource _eventCancellationTokenSource;
private CancellationTokenSource _eventCancellationTokenSource;
private ISettingsService _settingsService;
public ClientService()
public ClientService(ISettingsService settingsService)
{
this._settingsService = settingsService;
}
public MediaPausedEventHandler OnMediaPaused;
public NewMediaPlayingEventHandler OnNewMediaPlaying;
public PartyMemberJoinedEventHandler OnPartyMemberJoined;
public PartyMemberLeftEventHandler OnPartyMemberLeft;
public MediaResumedEventHandler OnMediaResumed;
public MediaPausedEventHandler OnMediaPaused { get; set; }
public NewMediaPlayingEventHandler OnNewMediaPlaying { get; set; }
public PartyMemberJoinedEventHandler OnPartyMemberJoined { get; set; }
public PartyMemberLeftEventHandler OnPartyMemberLeft { get; set; }
public MediaResumedEventHandler OnMediaResumed { get; set; }
public RemotePartyService.RemotePartyServiceClient RemotePartyClient
{
@ -94,10 +97,10 @@ namespace Aurora.Services.ClientService
public async Task GetEvents()
{
_eventCancellationTokenSource = new CancellationTokenSource();
string clientId = SettingsService.Instance.ClientId;
string clientId = this._settingsService.ClientId;
Console.WriteLine(string.Format("CLIENT {0} - GetEvents called from client with id", clientId));
using (AsyncServerStreamingCall<BaseEvent> eventStream = _remoteEventsClient
.GetEvents(new EventsRequest { ClientId = SettingsService.Instance.ClientId }))
.GetEvents(new EventsRequest { ClientId = this._settingsService.ClientId }))
{
try
{

View File

@ -0,0 +1,42 @@
using Aurora.Services.ClientService.Events;
using Aurora.Proto.Events;
using Aurora.Proto.Party;
using Aurora.Proto.Playback;
using Aurora.Proto.Sync;
using System.Threading.Tasks;
namespace Aurora.Services.ClientService
{
public interface IClientService
{
MediaPausedEventHandler OnMediaPaused { get; set; }
NewMediaPlayingEventHandler OnNewMediaPlaying { get; set; }
PartyMemberJoinedEventHandler OnPartyMemberJoined { get; set; }
PartyMemberLeftEventHandler OnPartyMemberLeft { get; set; }
MediaResumedEventHandler OnMediaResumed { get; set; }
RemotePartyService.RemotePartyServiceClient RemotePartyClient { get; }
RemoteEventService.RemoteEventServiceClient RemoteEventClient { get; }
RemotePlaybackService.RemotePlaybackServiceClient RemotePlaybackClient { get; }
RemoteSyncService.RemoteSyncServiceClient RemoteSyncClient { get; }
bool IsStarted { get; }
bool IsHost { get; set; }
void Start(string hostname, string port);
void Close();
/// <summary>
/// Asynchronous function for processing events off of the event stream.
/// </summary>
/// <returns></returns>
Task GetEvents();
void StopEvents();
}
}

View File

@ -0,0 +1,64 @@
using System;
using System.Threading.Tasks;
using System.Threading;
using Grpc.Core;
using Aurora.Models.Media;
using Aurora.Proto.Sync;
using LibVLCSharp.Shared;
namespace Aurora.Services.Player
{
public interface IPlayer
{
/// <summary>
/// Event handler for changing playback states.
/// </summary>
event PlaybackStateChangedEventHandler PlaybackStateChanged;
event MediaChangedEventHandler MediaChanged;
/// <summary>
/// The state of playback
/// </summary>
/// <value></value>
PlaybackState PlaybackState { get; }
bool IsLoaded { get; }
bool IsMediaLoaded(BaseMedia media);
BaseMedia CurrentMedia { get; }
float CurrentMediaPosition { get; }
long CurrentMediaLength { get; }
/// <summary>
/// Load media into the media player.
/// </summary>
/// <param name="media">Media to load</param>
Task LoadMedia(BaseMedia media);
/// <summary>
/// Play currently loaded media.
/// </summary>
void Play();
/// <summary>
/// Pause currently loaded media.
/// </summary>
void Pause();
/// <summary>
/// Stop currently loaded media.
/// </summary>
void Stop();
void Enqueue(BaseMedia song);
void Dequeue(BaseMedia song);
}
}

View File

@ -1,7 +1,7 @@
using System;
using Aurora.Models.Media;
namespace Aurora.Services.PlayerService
namespace Aurora.Services.Player
{
public delegate void MediaChangedEventHandler(object source, MediaChangedEventArgs e);

View File

@ -0,0 +1,12 @@
using System;
namespace Aurora.Services.Player
{
public enum PlaybackState
{
Playing,
Stopped,
Buffering,
}
}

View File

@ -1,7 +1,7 @@
using System;
using Aurora.Models.Media;
namespace Aurora.Services.PlayerService
namespace Aurora.Services.Player
{
public delegate void PlaybackStateChangedEventHandler(object source, PlaybackStateChangedEventArgs e);

View File

@ -6,10 +6,10 @@ using Aurora.Models.Media;
using Aurora.Proto.Sync;
using LibVLCSharp.Shared;
namespace Aurora.Services.PlayerService
namespace Aurora.Services.Player
{
public class PlayerService : BaseService<PlayerService>
public class PlayerService : BaseService<PlayerService>, IPlayer
{
private const long _ticksPerMillisecond = 10000;
private BaseMedia _currentMedia;

View File

@ -1,9 +0,0 @@
using System;
public enum PlaybackState
{
Playing,
Stopped,
Buffering,
}

View File

@ -0,0 +1,38 @@
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Aurora.Proto.PartyV2;
namespace Aurora.Services.Server.Controllers
{
public partial class RemotePartyController : RemotePartyService.RemotePartyServiceBase
{
/// <summary>
/// Constructor for partial class
/// </summary>
public RemotePartyController(string partyName, string description)
{
this._startDateTime = DateTime.UtcNow;
this._displayName = partyName;
this._description = description;
this._memberList = new SortedList<string, Member>();
this._mediaList = new SortedList<string, Models.Media.BaseMedia>();
string userName = "testUser";
this._eventManager = new EventManager.EventManager();
this._hostMember = new Member()
{
Name = GetNewMemberResourceName(_partyResourceName, ServerService.GetLocalIPAddress(), userName),
UserName = userName,
IpAddress = ServerService.GetLocalIPAddress(),
};
this._memberList.Add(_hostMember.Name, _hostMember);
//Add media from library
}
}
}

View File

@ -1,29 +1,158 @@
using System;
using System.Threading.Tasks;
using System.Collections.Generic;
using Aurora.Proto.PartyV2;
using Aurora.Models.Media;
using Aurora.Proto.General;
using Aurora.Services.Player;
using Autofac;
namespace Aurora.Services.Server.Controllers
{
public partial class RemotePartyController : RemotePartyService.RemotePartyServiceBase
{
private SortedList<string, BaseMedia> _mediaList;
public override Task<ListMediaResponse> ListMedia(ListMediaRequest request, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
ListMediaResponse resp = new ListMediaResponse();
int startIdx = 0;
if (!string.IsNullOrEmpty(request.PageToken))
{
startIdx = _memberList.IndexOfKey(request.PageToken) + 1;
}
int pageSize = request.PageSize;
if (pageSize > _mediaList.Count)
{
pageSize = _mediaList.Count;
}
//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
});
}
}
resp.NextPageToken = resp.Media[resp.Media.Count - 1].Name;
return Task.FromResult(resp);
}
public override Task<RemoteMedia> GetMedia(GetMediaRequest request, Grpc.Core.ServerCallContext context)
public override Task<Media> GetMedia(GetMediaRequest request, Grpc.Core.ServerCallContext context)
{
_mediaList.TryGetValue(request.Name, out BaseMedia 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);
}
public override Task<Media> CreateMedia(CreateMediaRequest request, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
}
public override Task StreamMedia(StreamMediaRequest request, Grpc.Core.IServerStreamWriter<Proto.General.Chunk> responseStream, Grpc.Core.ServerCallContext context)
public override Task<Empty> DeleteMedia(DeleteMediaRequest request, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
}
public override Task SyncMedia(SyncMediaRequest request, Grpc.Core.IServerStreamWriter<Sync> responseStream, Grpc.Core.ServerCallContext context)
public override async Task StreamMedia(StreamMediaRequest request, Grpc.Core.IServerStreamWriter<Proto.General.Chunk> responseStream, Grpc.Core.ServerCallContext context)
{
throw new NotImplementedException();
BaseMedia originalSong = LibraryService.Instance.GetSong(request.Name);
if (!(originalSong is LocalAudio))
{
return;
}
//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)
{
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);
}
}
public override async Task SyncMedia(SyncMediaRequest request, Grpc.Core.IServerStreamWriter<Sync> responseStream, Grpc.Core.ServerCallContext context)
{
bool continueSync = true;
using (var scope = App.Container.BeginLifetimeScope())
{
IPlayer player = scope.Resolve<IPlayer>();
string currentId = player.CurrentMedia.Id;
MediaChangedEventHandler mediaChanged = (sender, e) =>
{
if (e.NewId != currentId)
{
continueSync = false;
}
};
player.MediaChanged += mediaChanged;
while (continueSync)
{
float length = player.CurrentMediaLength;
Sync sync = new Sync()
{
TrackPosition = player.CurrentMediaPosition,
ServerTimeTicks = Utils.TimeUtils.GetNetworkTime().DateTime.Ticks
};
await responseStream.WriteAsync(sync);
Console.WriteLine("Sent Sync");
await Task.Delay(5000);
}
}
}
}
}

View File

@ -25,19 +25,21 @@ namespace Aurora.Services.Server.Controllers
startIdx = _memberList.IndexOfKey(request.PageToken) + 1;
}
int pageSize = request.PageSize;
//Assign pageSize
if (request.PageSize > _memberList.Count)
if (pageSize > _memberList.Count)
{
request.PageSize = _memberList.Count;
pageSize = _memberList.Count;
}
//Gather page
List<Member> members = new List<Member>(_memberList.Values);
resp.Members.AddRange(members.GetRange(startIdx, request.PageSize));
resp.Members.AddRange(members.GetRange(startIdx, pageSize));
//Set next page token
resp.NextPageToken = resp.Members[(startIdx + request.PageSize) - 1].Name;
resp.NextPageToken = resp.Members[resp.Members.Count - 1].Name;
return Task.FromResult(resp);
}

View File

@ -17,30 +17,6 @@ namespace Aurora.Services.Server.Controllers
private EventManager.EventManager _eventManager;
/// <summary>
/// Constructor for partial class
/// </summary>
public RemotePartyController(string partyName, string description)
{
this._startDateTime = DateTime.UtcNow;
this._displayName = partyName;
this._description = description;
this._memberList = new SortedList<string, Member>();
string userName = "testUser";
this._eventManager = new EventManager.EventManager();
this._hostMember = new Member()
{
Name = GetNewMemberResourceName(_partyResourceName, ServerService.GetLocalIPAddress(), userName),
UserName = userName,
IpAddress = ServerService.GetLocalIPAddress(),
};
this._memberList.Add(_hostMember.Name, _hostMember);
}
public override Task<Party> GetParty(Proto.General.Empty request, Grpc.Core.ServerCallContext context)
{
Party party = new Party()

View File

@ -8,13 +8,14 @@ using Aurora.Proto.Events;
using Aurora.Proto.Party;
using Aurora.Proto.Playback;
using Aurora.Proto.Sync;
using Aurora.Services.Settings;
using Autofac;
namespace Aurora.Services
{
public class ServerService : BaseService<ServerService>
{
private int _port = SettingsService.Instance.DefaultPort;
private int _port;
private string _hostname;
private Grpc.Core.Server _server;
@ -30,6 +31,11 @@ namespace Aurora.Services
public ServerService()
{
string host = GetLocalIPAddress();
using (var scope = App.Container.BeginLifetimeScope())
{
var service = scope.Resolve<ISettingsService>();
this._port = service.DefaultPort;
}
if (string.IsNullOrWhiteSpace(host))
{

View File

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

View File

@ -3,9 +3,9 @@ using System.Threading;
using Plugin.Settings;
using Plugin.Settings.Abstractions;
namespace Aurora.Services
namespace Aurora.Services.Settings
{
public class SettingsService : BaseService<SettingsService>
public class SettingsService : ISettingsService
{
private Lazy<ISettings> _appSettings;
private string _usernameKey = "username";