First pass at events almost buttoned up.
The goal is to get the members list to update when new users enter and leave the party.
This commit is contained in:
parent
74f5d3e9c6
commit
823e1341ca
@ -93,5 +93,7 @@
|
|||||||
Include="Proto\party.proto"/>
|
Include="Proto\party.proto"/>
|
||||||
<Protobuf
|
<Protobuf
|
||||||
Include="Proto\playback.proto"/>
|
Include="Proto\playback.proto"/>
|
||||||
|
<Protobuf
|
||||||
|
Include="Proto\events.proto"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
@ -2,7 +2,7 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
using Aurora.Proto;
|
using Aurora.Proto.Party;
|
||||||
|
|
||||||
namespace Aurora.Design.Components.MemberList
|
namespace Aurora.Design.Components.MemberList
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using Aurora.Executors;
|
using Aurora.Executors;
|
||||||
using Aurora.Proto;
|
using Aurora.Proto.Party;
|
||||||
using Xamarin.Forms;
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Aurora.Design.Views.Party
|
namespace Aurora.Design.Views.Party
|
||||||
@ -32,6 +32,15 @@ namespace Aurora.Design.Views.Party
|
|||||||
|
|
||||||
State(PartyState.SelectingHost);
|
State(PartyState.SelectingHost);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
~PartyViewModel()
|
||||||
|
{
|
||||||
|
if (_executor != null)
|
||||||
|
{
|
||||||
|
_executor.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
public ObservableCollection<PartyMember> Members
|
public ObservableCollection<PartyMember> Members
|
||||||
|
@ -2,8 +2,7 @@ using System;
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using Aurora.Proto;
|
using Aurora.Proto.Party;
|
||||||
|
|
||||||
namespace Aurora.Executors
|
namespace Aurora.Executors
|
||||||
{
|
{
|
||||||
public abstract class BaseExecutor
|
public abstract class BaseExecutor
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Threading;
|
||||||
using Grpc.Core;
|
using Grpc.Core;
|
||||||
using Aurora.Proto;
|
using wellKnown = Google.Protobuf.WellKnownTypes;
|
||||||
using Aurora.Models;
|
using Aurora.Proto.General;
|
||||||
|
using Aurora.Proto.Party;
|
||||||
|
using Aurora.Proto.Playback;
|
||||||
|
using Aurora.Proto.Events;
|
||||||
using Aurora.Services;
|
using Aurora.Services;
|
||||||
namespace Aurora.Executors
|
namespace Aurora.Executors
|
||||||
{
|
{
|
||||||
@ -11,6 +16,8 @@ namespace Aurora.Executors
|
|||||||
private Channel _channel;
|
private Channel _channel;
|
||||||
private RemotePartyService.RemotePartyServiceClient _remotePartyClient;
|
private RemotePartyService.RemotePartyServiceClient _remotePartyClient;
|
||||||
private RemotePlaybackService.RemotePlaybackServiceClient _remotePlaybackClient;
|
private RemotePlaybackService.RemotePlaybackServiceClient _remotePlaybackClient;
|
||||||
|
private RemoteEventService.RemoteEventServiceClient _remoteEventsClient;
|
||||||
|
private Task _eventsTask;
|
||||||
|
|
||||||
private ObservableCollection<PartyMember> _partyMembers;
|
private ObservableCollection<PartyMember> _partyMembers;
|
||||||
|
|
||||||
@ -27,16 +34,28 @@ namespace Aurora.Executors
|
|||||||
|
|
||||||
#endregion Properties
|
#endregion Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initiates the connection to a party.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="hostname">The hostname of the gRPC server</param>
|
||||||
public override void Connect(string hostname)
|
public override void Connect(string hostname)
|
||||||
{
|
{
|
||||||
_channel = new Channel(string.Format("{0}:{1}", hostname, SettingsService.Instance.DefaultPort), ChannelCredentials.Insecure);
|
_channel = new Channel(string.Format("{0}:{1}", hostname, SettingsService.Instance.DefaultPort), ChannelCredentials.Insecure);
|
||||||
|
|
||||||
_remotePartyClient = new RemotePartyService.RemotePartyServiceClient(_channel);
|
_remotePartyClient = new RemotePartyService.RemotePartyServiceClient(_channel);
|
||||||
_remotePlaybackClient = new RemotePlaybackService.RemotePlaybackServiceClient(_channel);
|
_remotePlaybackClient = new RemotePlaybackService.RemotePlaybackServiceClient(_channel);
|
||||||
|
_remoteEventsClient = new RemoteEventService.RemoteEventServiceClient(_channel);
|
||||||
|
|
||||||
|
//Assign but don't start task
|
||||||
|
_eventsTask = new Task(GetEvents);
|
||||||
|
|
||||||
JoinParty();
|
JoinParty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Shutdown Connections
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
public override async void Close()
|
public override async void Close()
|
||||||
{
|
{
|
||||||
await _channel.ShutdownAsync();
|
await _channel.ShutdownAsync();
|
||||||
@ -69,6 +88,28 @@ namespace Aurora.Executors
|
|||||||
UserName = SettingsService.Instance.Username,
|
UserName = SettingsService.Instance.Username,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
RefreshMembers();
|
||||||
|
|
||||||
|
//Subscribe to events
|
||||||
|
SubscribeRequest req = new SubscribeRequest();
|
||||||
|
req.EventTypes.Add(EventType.PartyMemberJoined);
|
||||||
|
req.EventTypes.Add(EventType.PartyMemberLeft);
|
||||||
|
try
|
||||||
|
{
|
||||||
|
_remoteEventsClient.SubscribeToEvents(req);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Console.WriteLine("Error subscribing to events: " + ex.Message);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_eventsTask.Start();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RefreshMembers()
|
||||||
|
{
|
||||||
MembersResponse resposne = _remotePartyClient.GetPartyMembers(new Empty());
|
MembersResponse resposne = _remotePartyClient.GetPartyMembers(new Empty());
|
||||||
//Add members
|
//Add members
|
||||||
foreach (PartyMember member in resposne.Members)
|
foreach (PartyMember member in resposne.Members)
|
||||||
@ -85,5 +126,36 @@ namespace Aurora.Executors
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async void GetEvents()
|
||||||
|
{
|
||||||
|
|
||||||
|
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
|
||||||
|
using (AsyncServerStreamingCall<BaseEvent> eventStream = _remoteEventsClient.GetEvents(new Empty()))
|
||||||
|
{
|
||||||
|
while (await eventStream.ResponseStream.MoveNext(cancellationTokenSource.Token))
|
||||||
|
{
|
||||||
|
//Convert derived event type
|
||||||
|
BaseEvent e = eventStream.ResponseStream.Current;
|
||||||
|
switch (e.DerivedEventCase)
|
||||||
|
{
|
||||||
|
case BaseEvent.DerivedEventOneofCase.None:
|
||||||
|
{
|
||||||
|
throw new InvalidOperationException();
|
||||||
|
}
|
||||||
|
case BaseEvent.DerivedEventOneofCase.PartyMemberJoinedEvent:
|
||||||
|
{
|
||||||
|
PartyMemberJoinedEvent derivedEvent = e.PartyMemberJoinedEvent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case BaseEvent.DerivedEventOneofCase.PartyMemberLeftEvent:
|
||||||
|
{
|
||||||
|
PartyMemberJoinedEvent derivedEvent = e.PartyMemberJoinedEvent;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -4,7 +4,9 @@ using System.Collections.ObjectModel;
|
|||||||
using Aurora.Models;
|
using Aurora.Models;
|
||||||
using Aurora.Executors;
|
using Aurora.Executors;
|
||||||
using Aurora.Services;
|
using Aurora.Services;
|
||||||
using Aurora.Proto;
|
using Aurora.Proto.Party;
|
||||||
|
using Aurora.Proto.Playback;
|
||||||
|
using Aurora.Proto.Events;
|
||||||
using Aurora.RemoteImpl;
|
using Aurora.RemoteImpl;
|
||||||
|
|
||||||
namespace Aurora.Executors
|
namespace Aurora.Executors
|
||||||
@ -13,10 +15,12 @@ namespace Aurora.Executors
|
|||||||
{
|
{
|
||||||
RemotePartyServiceImpl _remotePartyServiceImpl;
|
RemotePartyServiceImpl _remotePartyServiceImpl;
|
||||||
RemotePlaybackServiceImpl _remotePlaybackImpl;
|
RemotePlaybackServiceImpl _remotePlaybackImpl;
|
||||||
|
RemoteEventServiceImpl _remoteEventImpl;
|
||||||
public HostExecutor()
|
public HostExecutor()
|
||||||
{
|
{
|
||||||
_remotePartyServiceImpl = new RemotePartyServiceImpl();
|
_remotePartyServiceImpl = new RemotePartyServiceImpl();
|
||||||
_remotePlaybackImpl = new RemotePlaybackServiceImpl();
|
_remotePlaybackImpl = new RemotePlaybackServiceImpl();
|
||||||
|
_remoteEventImpl = new RemoteEventServiceImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void Connect(string hostname)
|
public override void Connect(string hostname)
|
||||||
@ -27,6 +31,7 @@ namespace Aurora.Executors
|
|||||||
//Register grpc RemoteService with singleton server service
|
//Register grpc RemoteService with singleton server service
|
||||||
ServerService.Instance.RegisterService(RemotePartyService.BindService(_remotePartyServiceImpl));
|
ServerService.Instance.RegisterService(RemotePartyService.BindService(_remotePartyServiceImpl));
|
||||||
ServerService.Instance.RegisterService(RemotePlaybackService.BindService(_remotePlaybackImpl));
|
ServerService.Instance.RegisterService(RemotePlaybackService.BindService(_remotePlaybackImpl));
|
||||||
|
ServerService.Instance.RegisterService(RemoteEventService.BindService(_remoteEventImpl));
|
||||||
|
|
||||||
//start gRPC server
|
//start gRPC server
|
||||||
ServerService.Instance.Start();
|
ServerService.Instance.Start();
|
||||||
|
51
Aurora/Proto/events.proto
Normal file
51
Aurora/Proto/events.proto
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package Aurora.Proto.Events;
|
||||||
|
|
||||||
|
import "Proto/general.proto";
|
||||||
|
import "Proto/party.proto";
|
||||||
|
|
||||||
|
service RemoteEventService {
|
||||||
|
//Party Service
|
||||||
|
rpc GetEvents(Aurora.Proto.General.Empty) returns (stream BaseEvent) {};
|
||||||
|
rpc SubscribeToEvents(SubscribeRequest) returns(SubscriptionResponse);
|
||||||
|
rpc UnsubscribeFromEvents(UnsubscribeRequest) returns (SubscriptionResponse);
|
||||||
|
rpc UnsubscribeFromAll(UnsubscribeAllRequest) returns (SubscriptionResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subscription messages */
|
||||||
|
message SubscribeRequest {
|
||||||
|
repeated EventType eventTypes = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UnsubscribeRequest {
|
||||||
|
repeated EventType eventTypes = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message UnsubscribeAllRequest {
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscriptionResponse {
|
||||||
|
bool successful = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Event Types */
|
||||||
|
enum EventType {
|
||||||
|
PartyMemberJoined = 0;
|
||||||
|
PartyMemberLeft = 1;
|
||||||
|
}
|
||||||
|
message BaseEvent {
|
||||||
|
EventType eventType = 1;
|
||||||
|
oneof derivedEvent {
|
||||||
|
PartyMemberJoinedEvent partyMemberJoinedEvent = 2;
|
||||||
|
PartyMemberLeftEvent partyMemberLeftEvent = 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
message PartyMemberJoinedEvent {
|
||||||
|
Aurora.Proto.Party.PartyMember member = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message PartyMemberLeftEvent {
|
||||||
|
Aurora.Proto.Party.PartyMember member = 2;
|
||||||
|
}
|
@ -1,10 +1,10 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package Aurora.Proto;
|
package Aurora.Proto.General;
|
||||||
|
|
||||||
message Chunk {
|
message Chunk {
|
||||||
bytes Content = 1;
|
bytes Content = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Empty{
|
message Empty{
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package Aurora.Proto;
|
package Aurora.Proto.Party;
|
||||||
|
|
||||||
import "Proto/general.proto";
|
import "Proto/general.proto";
|
||||||
|
|
||||||
@ -8,7 +8,7 @@ service RemotePartyService {
|
|||||||
//Party Service
|
//Party Service
|
||||||
rpc JoinParty(JoinPartyRequest) returns (JoinPartyResponse);
|
rpc JoinParty(JoinPartyRequest) returns (JoinPartyResponse);
|
||||||
rpc LeaveParty(LeavePartyRequest) returns (LeavePartyResponse);
|
rpc LeaveParty(LeavePartyRequest) returns (LeavePartyResponse);
|
||||||
rpc GetPartyMembers(Empty) returns (MembersResponse);
|
rpc GetPartyMembers(Aurora.Proto.General.Empty) returns (MembersResponse);
|
||||||
}
|
}
|
||||||
|
|
||||||
message JoinPartyRequest {
|
message JoinPartyRequest {
|
||||||
|
@ -1,12 +1,12 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package Aurora.Proto;
|
package Aurora.Proto.Playback;
|
||||||
|
|
||||||
import "Proto/general.proto";
|
import "Proto/general.proto";
|
||||||
|
|
||||||
service RemotePlaybackService {
|
service RemotePlaybackService {
|
||||||
//Playback Service
|
//Playback Service
|
||||||
rpc GetPartyStream(Empty) returns (stream Chunk) {};
|
rpc GetPartyStream(Aurora.Proto.General.Empty) returns (stream Aurora.Proto.General.Chunk) {};
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TransferStatusCode {
|
enum TransferStatusCode {
|
||||||
|
80
Aurora/RemoteImpl/RemoteEventImpl.cs
Normal file
80
Aurora/RemoteImpl/RemoteEventImpl.cs
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Aurora.Services;
|
||||||
|
using Aurora.Proto.Events;
|
||||||
|
using Aurora.Proto.General;
|
||||||
|
|
||||||
|
namespace Aurora.RemoteImpl
|
||||||
|
{
|
||||||
|
public class RemoteEventServiceImpl : RemoteEventService.RemoteEventServiceBase
|
||||||
|
{
|
||||||
|
public RemoteEventServiceImpl()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RPC for getting event stream for a particular client.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">Empty</param>
|
||||||
|
/// <param name="responseStream">The response stream</param>
|
||||||
|
/// <param name="context">gRPC client context</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public async override Task GetEvents(Empty request, Grpc.Core.IServerStreamWriter<BaseEvent> responseStream, Grpc.Core.ServerCallContext context)
|
||||||
|
{
|
||||||
|
while (EventManager.Instance.GetSubscriptionCount(context.Peer) > 0)
|
||||||
|
{
|
||||||
|
List<BaseEvent> events = EventManager.Instance.GetSessionEvents(context.Peer);
|
||||||
|
foreach (BaseEvent currentEvent in events)
|
||||||
|
{
|
||||||
|
await responseStream.WriteAsync(currentEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RPC for subscribing to remote events
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">SubscribeRequest</param>
|
||||||
|
/// <param name="context">gRPC client context</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override Task<SubscriptionResponse> SubscribeToEvents(SubscribeRequest request, Grpc.Core.ServerCallContext context)
|
||||||
|
{
|
||||||
|
EventManager.Instance.AddSubscriptionList(context.Peer, request.EventTypes.ToList());
|
||||||
|
|
||||||
|
return Task.FromResult(new SubscriptionResponse { Successful = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RPC for unsubscibing from events
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">UnsubscribeRequest</param>
|
||||||
|
/// <param name="context">gRPC client context</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override Task<SubscriptionResponse> UnsubscribeFromEvents(UnsubscribeRequest request, Grpc.Core.ServerCallContext context)
|
||||||
|
{
|
||||||
|
EventType[] eventTypes = null;
|
||||||
|
request.EventTypes.CopyTo(eventTypes, 0);
|
||||||
|
|
||||||
|
EventManager.Instance.RemoveSubscriptionList(context.Peer, eventTypes.ToList());
|
||||||
|
|
||||||
|
return Task.FromResult(new SubscriptionResponse { Successful = true });
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RPC for unsubscribing from all events
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="request">UnsubscribeAllRequest</param>
|
||||||
|
/// <param name="context">gRPC client context</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public override Task<SubscriptionResponse> UnsubscribeFromAll(UnsubscribeAllRequest request, Grpc.Core.ServerCallContext context)
|
||||||
|
{
|
||||||
|
EventManager.Instance.RemoveAllSubscriptions(context.Peer);
|
||||||
|
|
||||||
|
return Task.FromResult(new SubscriptionResponse { Successful = true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -2,7 +2,10 @@ using System;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Aurora.Proto;
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
using Aurora.Proto.Party;
|
||||||
|
using Aurora.Proto.General;
|
||||||
|
using Aurora.Proto.Events;
|
||||||
using Aurora.Models;
|
using Aurora.Models;
|
||||||
using Aurora.Services;
|
using Aurora.Services;
|
||||||
|
|
||||||
@ -39,11 +42,24 @@ namespace Aurora.RemoteImpl
|
|||||||
|
|
||||||
public override Task<JoinPartyResponse> JoinParty(JoinPartyRequest request, Grpc.Core.ServerCallContext context)
|
public override Task<JoinPartyResponse> JoinParty(JoinPartyRequest request, Grpc.Core.ServerCallContext context)
|
||||||
{
|
{
|
||||||
_partyMembers.Add(new PartyMember()
|
PartyMember partyMember = new PartyMember()
|
||||||
{
|
{
|
||||||
UserName = request.UserName,
|
UserName = request.UserName,
|
||||||
IpAddress = context.Host,
|
IpAddress = context.Host,
|
||||||
});
|
};
|
||||||
|
|
||||||
|
_partyMembers.Add(partyMember);
|
||||||
|
|
||||||
|
BaseEvent e = new BaseEvent
|
||||||
|
{
|
||||||
|
EventType = EventType.PartyMemberJoined,
|
||||||
|
PartyMemberJoinedEvent = new PartyMemberJoinedEvent
|
||||||
|
{
|
||||||
|
Member = partyMember,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EventManager.Instance.PushEvent(e);
|
||||||
|
|
||||||
JoinPartyResponse response = new JoinPartyResponse() { Status = PartyJoinedStatusEnum.Connected };
|
JoinPartyResponse response = new JoinPartyResponse() { Status = PartyJoinedStatusEnum.Connected };
|
||||||
return Task.FromResult(response);
|
return Task.FromResult(response);
|
||||||
@ -51,12 +67,26 @@ namespace Aurora.RemoteImpl
|
|||||||
|
|
||||||
public override Task<LeavePartyResponse> LeaveParty(LeavePartyRequest request, Grpc.Core.ServerCallContext context)
|
public override Task<LeavePartyResponse> LeaveParty(LeavePartyRequest request, Grpc.Core.ServerCallContext context)
|
||||||
{
|
{
|
||||||
_partyMembers.Remove(_partyMembers.Where(e => e.Id == request.ClientId).Single());
|
PartyMember partyMember = _partyMembers.Where(e => e.Id == request.ClientId).Single();
|
||||||
|
|
||||||
|
_partyMembers.Remove(partyMember);
|
||||||
|
|
||||||
|
BaseEvent bv = new BaseEvent
|
||||||
|
{
|
||||||
|
EventType = EventType.PartyMemberJoined,
|
||||||
|
PartyMemberLeftEvent = new PartyMemberLeftEvent
|
||||||
|
{
|
||||||
|
Member = partyMember,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EventManager.Instance.PushEvent(bv);
|
||||||
|
|
||||||
LeavePartyResponse response = new LeavePartyResponse() { Status = PartyJoinedStatusEnum.Disconnected };
|
LeavePartyResponse response = new LeavePartyResponse() { Status = PartyJoinedStatusEnum.Disconnected };
|
||||||
return Task.FromResult(response);
|
return Task.FromResult(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override Task<MembersResponse> GetPartyMembers(Empty empty, Grpc.Core.ServerCallContext context)
|
public override Task<MembersResponse> GetPartyMembers(Proto.General.Empty empty, Grpc.Core.ServerCallContext context)
|
||||||
{
|
{
|
||||||
MembersResponse response = new MembersResponse();
|
MembersResponse response = new MembersResponse();
|
||||||
response.Members.AddRange(_partyMembers);
|
response.Members.AddRange(_partyMembers);
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using Aurora.Proto;
|
using Aurora.Proto.Playback;
|
||||||
|
using Aurora.Proto.General;
|
||||||
using Aurora.Models;
|
using Aurora.Models;
|
||||||
|
|
||||||
namespace Aurora.RemoteImpl
|
namespace Aurora.RemoteImpl
|
||||||
@ -14,7 +15,7 @@ namespace Aurora.RemoteImpl
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task GetPartyStream(Empty empty,
|
public override Task GetPartyStream(Empty empty,
|
||||||
Grpc.Core.IServerStreamWriter<Chunk> responseStream,
|
Grpc.Core.IServerStreamWriter<Chunk> responseStream,
|
||||||
Grpc.Core.ServerCallContext context)
|
Grpc.Core.ServerCallContext context)
|
||||||
{
|
{
|
||||||
|
294
Aurora/Services/EventManager.cs
Executable file
294
Aurora/Services/EventManager.cs
Executable file
@ -0,0 +1,294 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using Google.Protobuf.WellKnownTypes;
|
||||||
|
using Google.Protobuf.Reflection;
|
||||||
|
using Aurora.Proto.Events;
|
||||||
|
using Aurora.Models;
|
||||||
|
|
||||||
|
namespace Aurora.Services
|
||||||
|
{
|
||||||
|
public class EventManager : BaseService<EventManager>
|
||||||
|
{
|
||||||
|
//TODO purge inactive sessions from the list
|
||||||
|
public EventManager()
|
||||||
|
{
|
||||||
|
_eventQueues = new ConcurrentDictionary<string, BlockingCollection<BaseEvent>>();
|
||||||
|
_subscriptionList = new Dictionary<string, List<EventType>>();
|
||||||
|
_unprocessedEventsList = new ObservableCollection<BaseEvent>();
|
||||||
|
_unprocessedEventsList.CollectionChanged += UnprocessedEventsList_Changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
private ConcurrentDictionary<string, BlockingCollection<BaseEvent>> _eventQueues;
|
||||||
|
private Dictionary<string, List<EventType>> _subscriptionList;
|
||||||
|
private ObservableCollection<BaseEvent> _unprocessedEventsList;
|
||||||
|
|
||||||
|
|
||||||
|
#endregion Fields
|
||||||
|
|
||||||
|
#region Private Methods
|
||||||
|
/// <summary>
|
||||||
|
/// Add event to appropriate events list for subscribed sessions
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="unprocessedEvent"></param>
|
||||||
|
private void ProcessEvent(BaseEvent unprocessedEvent)
|
||||||
|
{
|
||||||
|
lock (_subscriptionList)
|
||||||
|
{
|
||||||
|
lock (_unprocessedEventsList)
|
||||||
|
{
|
||||||
|
//Duplicate events into client event queues
|
||||||
|
foreach (KeyValuePair<string, List<EventType>> subscription in _subscriptionList)
|
||||||
|
{
|
||||||
|
//Active Events contains the session in question
|
||||||
|
if (_eventQueues.ContainsKey(subscription.Key))
|
||||||
|
{
|
||||||
|
//Add all of the events to active events that are subscribed
|
||||||
|
|
||||||
|
if (subscription.Value.Contains(unprocessedEvent.EventType))
|
||||||
|
{
|
||||||
|
BlockingCollection<BaseEvent> eventList;
|
||||||
|
_eventQueues.TryGetValue(subscription.Key, out eventList);
|
||||||
|
if (eventList != null)
|
||||||
|
{
|
||||||
|
eventList.Add(unprocessedEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Remove Event from list
|
||||||
|
_unprocessedEventsList.Remove(unprocessedEvent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Private Methods
|
||||||
|
|
||||||
|
#region Public Methods
|
||||||
|
/// <summary>
|
||||||
|
/// Get the list of event type subscriptions for a given session id.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session">Session Id</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<EventType> GetSubscriptionList(string session)
|
||||||
|
{
|
||||||
|
List<EventType> eventList = new List<EventType>();
|
||||||
|
if (_subscriptionList.ContainsKey(session))
|
||||||
|
{
|
||||||
|
_subscriptionList.TryGetValue(session, out eventList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get the number of event subscriptions for a given session
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session">Session Id</param>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int GetSubscriptionCount(string session)
|
||||||
|
{
|
||||||
|
List<EventType> eventList = new List<EventType>();
|
||||||
|
if (_subscriptionList.ContainsKey(session))
|
||||||
|
{
|
||||||
|
_subscriptionList.TryGetValue(session, out eventList);
|
||||||
|
}
|
||||||
|
|
||||||
|
return eventList.Count();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a new subscription
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session"></param>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
public bool AddSubscription(string session, EventType type)
|
||||||
|
{
|
||||||
|
bool success = false;
|
||||||
|
if (!_subscriptionList.ContainsKey(session))
|
||||||
|
{
|
||||||
|
//Add session to subscription list
|
||||||
|
List<EventType> eventList = new List<EventType>();
|
||||||
|
eventList.Add(type);
|
||||||
|
_subscriptionList.Add(session, eventList);
|
||||||
|
success = true;
|
||||||
|
//base.LogInformation(string.Format("Subscription removed for event type {0} subscription on session {1}", type.ToString(), session));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
List<EventType> eventList;
|
||||||
|
_subscriptionList.TryGetValue(session, out eventList);
|
||||||
|
if (eventList != null)
|
||||||
|
{
|
||||||
|
eventList.Add(type);
|
||||||
|
success = true;
|
||||||
|
//base.LogInformation(string.Format("Subscription removed for event type {0} subscription on session {1}", type.ToString(), session));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//Add activeEvents if it doesn't exist
|
||||||
|
if (!_eventQueues.ContainsKey(session))
|
||||||
|
{
|
||||||
|
//Add session to active events
|
||||||
|
_eventQueues.TryAdd(session, new BlockingCollection<BaseEvent>());
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a list of subscriptions. This unsubscribes from unused events.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session">The browser session id.</param>
|
||||||
|
/// <param name="types">The list of event types to subscribe to.</param>
|
||||||
|
public void AddSubscriptionList(string session, List<EventType> types)
|
||||||
|
{
|
||||||
|
RemoveAllSubscriptions(session);
|
||||||
|
|
||||||
|
foreach (EventType e in types)
|
||||||
|
{
|
||||||
|
AddSubscription(session, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Unsubscribe from a given event type.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session">Session Id</param>
|
||||||
|
/// <param name="type">Event Type to be removed</param>
|
||||||
|
public void RemoveSubscription(string session, EventType type)
|
||||||
|
{
|
||||||
|
if (_subscriptionList.ContainsKey(session))
|
||||||
|
{
|
||||||
|
List<EventType> eventTypeList;
|
||||||
|
_subscriptionList.TryGetValue(session, out eventTypeList);
|
||||||
|
if (eventTypeList != null && eventTypeList.Contains(type))
|
||||||
|
{
|
||||||
|
eventTypeList.Remove(type);
|
||||||
|
//base.LogInformation(string.Format("Subscription removed for event type {0} subscription on session {1}", type.ToString(), session));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveSubscriptionList(string session, List<EventType> types)
|
||||||
|
{
|
||||||
|
foreach (EventType e in types)
|
||||||
|
{
|
||||||
|
RemoveSubscription(session, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Remove all subscriptons for a given session.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session">Session Id</param>
|
||||||
|
public void RemoveAllSubscriptions(string session)
|
||||||
|
{
|
||||||
|
if (_subscriptionList.ContainsKey(session))
|
||||||
|
{
|
||||||
|
_subscriptionList.Remove(session);
|
||||||
|
}
|
||||||
|
if (_eventQueues.ContainsKey(session))
|
||||||
|
{
|
||||||
|
BlockingCollection<BaseEvent> rem = null;
|
||||||
|
_eventQueues.TryRemove(session, out rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
//base.LogInformation(string.Format("All subscriptions removed for event type {0}", session));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Get a list of accumulated events for a given session. Timeout after 5 seconds if list is empty.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="session"></param>
|
||||||
|
/// <returns>List<BaseEvent></returns>
|
||||||
|
public List<BaseEvent> GetSessionEvents(string session)
|
||||||
|
{
|
||||||
|
BlockingCollection<BaseEvent> eList;
|
||||||
|
_eventQueues.TryGetValue(session, out eList);
|
||||||
|
|
||||||
|
List<BaseEvent> returnList = new List<BaseEvent>();
|
||||||
|
if (eList == null)
|
||||||
|
{
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Continue to take until the eList is not empty.
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
BaseEvent e;
|
||||||
|
eList.TryTake(out e);
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
returnList.Add(e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//In the event that eList was empty to begin with, wait for something to be appear or cancel
|
||||||
|
if (eList.Count == 0)
|
||||||
|
{
|
||||||
|
CancellationTokenSource tkSrc = new CancellationTokenSource(5000);
|
||||||
|
|
||||||
|
BaseEvent e = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
e = eList.Take(tkSrc.Token);
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
// eat this
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
if (e != null)
|
||||||
|
{
|
||||||
|
returnList.Add(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnList;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Push a new event to the event queue.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="newEvent">The event to be pushed</param>
|
||||||
|
public void PushEvent(BaseEvent newEvent)
|
||||||
|
{
|
||||||
|
_unprocessedEventsList.Add(newEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Public Methods
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
private void UnprocessedEventsList_Changed(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
switch (e.Action)
|
||||||
|
{
|
||||||
|
case NotifyCollectionChangedAction.Add:
|
||||||
|
{
|
||||||
|
foreach (BaseEvent bEvent in e.NewItems)
|
||||||
|
{
|
||||||
|
ProcessEvent(bEvent);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion Events
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user