Archived
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:
1 parent
74f5d3e9c6
commit
823e1341ca
14 files changed
+562
-19
No files matched your search
@@ -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();
|
||||||
|
|||||||
@@ -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,6 +1,6 @@
|
|||||||
syntax = "proto3";
|
syntax = "proto3";
|
||||||
|
|
||||||
package Aurora.Proto;
|
package Aurora.Proto.General;
|
||||||
|
|
||||||
message Chunk {
|
message Chunk {
|
||||||
bytes Content = 1;
|
bytes Content = 1;
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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)
|
||||||
{
|
{
|
||||||
|
|||||||
Executable
+294
@@ -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