Skip to content
This repository was archived by the owner on Oct 28, 2021. It is now read-only.

Added support for a continous feed of connection request updates. #15

Merged
merged 2 commits into from
Aug 1, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 115 additions & 0 deletions src/SymphonyOSS.RestApiClient/Api/PodApi/ConnectionApi.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,13 @@ namespace SymphonyOSS.RestApiClient.Api.PodApi
{
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using AgentApi;
using Authentication;
using Generated.OpenApi.AgentApi.Model;
using Generated.OpenApi.PodApi.Client;
using Generated.OpenApi.PodApi.Model;

Expand All @@ -30,12 +36,37 @@ namespace SymphonyOSS.RestApiClient.Api.PodApi
/// </summary>
public class ConnectionApi
{
private static readonly TraceSource TraceSource = new TraceSource("SymphonyOSS.RestApiClient");

private readonly Generated.OpenApi.PodApi.Api.IConnectionApi _connectionApi;

private readonly IAuthTokens _authTokens;

private readonly IApiExecutor _apiExecutor;

private readonly Dictionary<EventHandler<ConnectionRequestEventArgs>, Task> _tasks =
new Dictionary<EventHandler<ConnectionRequestEventArgs>, Task>();

private Timer _connectionPollTimer;

private event EventHandler<ConnectionRequestEventArgs> _onConnectionRequest;

public event EventHandler<ConnectionRequestEventArgs> OnConnectionRequest
{
add
{
_onConnectionRequest += value;
}
remove
{
_onConnectionRequest -= value;
lock (_tasks)
{
_tasks.Remove(value);
}
}
}

/// <summary>
/// Initializes a new instance of the <see cref="UsersApi" /> class.
/// See <see cref="Factories.PodApiFactory"/> for conveniently constructing
Expand All @@ -51,6 +82,54 @@ public ConnectionApi(IAuthTokens authTokens, Configuration configuration, IApiEx
_apiExecutor = apiExecutor;
}

/// <summary>
/// Starts listening, notifying event handlers about incoming connection requests. Blocks
/// until <see cref="ConnectionApi.Stop"/> is invoked.
/// </summary>
public void Listen(long timeout)
{
_connectionPollTimer = new Timer(
cb =>
{
try
{
var connectionList =
List().Where(connection => connection.Status != UserConnection.StatusEnum.Accepted);

ProcessConnectionList(connectionList);
}
catch (Exception ex)
{
TraceSource.TraceEvent(
TraceEventType.Error, 0,
"Unhandled exception caught when fecthing list of connection request {1}",
ex);
}
}, null, 0, timeout);
}

/// <summary>
/// Requests that <see cref="Listen"/> should stop.
/// </summary>
public void Stop()
{
_connectionPollTimer.Dispose();
_connectionPollTimer = null;
}

protected void ProcessConnectionList(IEnumerable<UserConnection> connectionList)
{
if (connectionList == null || _onConnectionRequest == null)
{
return;
}

foreach (var eventHandler in _onConnectionRequest.GetInvocationList())
{
NotifyAsync((EventHandler<ConnectionRequestEventArgs>)eventHandler, connectionList);
}
}

/// <summary>
/// Get the status of a connection invitation to another user.
/// </summary>
Expand Down Expand Up @@ -120,5 +199,41 @@ private string GetStatusAsString(UserConnection.StatusEnum status)
return status.ToString().ToLower();
}
}

protected async void NotifyAsync(EventHandler<ConnectionRequestEventArgs> connectionEventHandler,
IEnumerable<UserConnection> connectionList)
{
// Notify each handler in a separate task, maintaining the order of connections in the list, and
// get back to reading the connectio list again without waiting for listeners to process connection requests.
Task task;
if (_tasks.TryGetValue(connectionEventHandler, out task))
{
await task;
}
_tasks[connectionEventHandler] = Task.Run(() => Notify(connectionEventHandler, connectionList));
}

private void Notify(EventHandler<ConnectionRequestEventArgs> connectionEventHandler,
IEnumerable<UserConnection> connectionList)
{
foreach (var connection in connectionList)
{
TraceSource.TraceEvent(
TraceEventType.Verbose, 0,
"Notifying listener about connection request for user with ID \"{0}\" and status \"{1}\"",
connection?.UserId, connection?.Status);
try
{
connectionEventHandler.Invoke(this, new ConnectionRequestEventArgs(connection));
}
catch (Exception e)
{
TraceSource.TraceEvent(
TraceEventType.Error, 0,
"Unhandled exception caught when notifying listener about connection request for user with ID \"{0}\": {1}",
connection?.UserId, e);
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
namespace SymphonyOSS.RestApiClient.Api.PodApi
{
using System;
using Generated.OpenApi.PodApi.Model;

/// <summary>
/// Event data for connection requests.
/// </summary>
public class ConnectionRequestEventArgs : EventArgs
{
public ConnectionRequestEventArgs(UserConnection connection)
{
Connection = connection;
}

public UserConnection Connection { get; private set; }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
<Compile Include="Api\AgentApi\MessagesApi.cs" />
<Compile Include="Api\AgentApi\UtilApi.cs" />
<Compile Include="Api\IRetryStrategy.cs" />
<Compile Include="Api\PodApi\ConnectionRequestEventArgs.cs" />
<Compile Include="Api\PodApi\RoomMembershipApi.cs" />
<Compile Include="Api\PodApi\SecurityApi.cs" />
<Compile Include="Api\PodApi\UserApi.cs" />
Expand Down