Backup and Clean Push Service and implement new Structure of Push Service ...
This commit is contained in:
+20
-361
@@ -1,404 +1,63 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xCommons.Extensions;
|
||||
using xModels.Dtos;
|
||||
using xPushService.Constants;
|
||||
using xPushService.Interfaces;
|
||||
using xPushService.Models;
|
||||
|
||||
namespace xPushService.Base {
|
||||
/// <summary>
|
||||
/// a base class for implementing Hubs ...
|
||||
/// </summary>
|
||||
namespace xPushService.Base
|
||||
{
|
||||
public abstract class XBaseHub : Hub, IXBaseHub
|
||||
{
|
||||
//
|
||||
#region Props ...
|
||||
protected readonly IXPushGroupStore groupStore;
|
||||
protected readonly IXPushConnectionStore connectionStore;
|
||||
protected readonly ILogger<XBaseHub> logger;
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Constructor ...
|
||||
public XBaseHub(
|
||||
IXPushGroupStore groupStore,
|
||||
IXPushConnectionStore connectionStore
|
||||
) : base()
|
||||
ILogger<XBaseHub> logger
|
||||
)
|
||||
{
|
||||
//
|
||||
this.groupStore = groupStore;
|
||||
this.connectionStore = connectionStore;
|
||||
this.logger = logger;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Abstract ...
|
||||
public abstract XPushConnectionDto GetConnection();
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region EnevtHandlers ...
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Overrides ...
|
||||
public override Task OnConnectedAsync()
|
||||
public override async Task OnConnectedAsync()
|
||||
{
|
||||
//
|
||||
var connection = GetConnection();
|
||||
if (!connection.IsNull())
|
||||
var connectionId = Context.ConnectionId;
|
||||
if (!connectionId.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
connectionStore
|
||||
.Add(connection)
|
||||
.RunTask();
|
||||
|
||||
//
|
||||
var count = connectionStore
|
||||
.Count()
|
||||
.RunTask();
|
||||
|
||||
//
|
||||
Console.WriteLine($"Count After Coonected: {count}");
|
||||
// Notify Other Clients Which a new Connection Joins ...
|
||||
await Clients.AllExcept(connectionId).SendAsync(XBaseHubAction.NewConnection.GetStringValue(), connectionId);
|
||||
}
|
||||
|
||||
//
|
||||
return base.OnConnectedAsync();
|
||||
await base.OnConnectedAsync();
|
||||
}
|
||||
|
||||
public override Task OnDisconnectedAsync(Exception exception)
|
||||
public override async Task OnDisconnectedAsync(Exception exception)
|
||||
{
|
||||
//
|
||||
var connection = GetConnection();
|
||||
if (!connection.IsNull())
|
||||
var connectionId = Context.ConnectionId;
|
||||
if (!connectionId.IsNullOrEmpty())
|
||||
{
|
||||
//
|
||||
connectionStore
|
||||
.RemoveByConnectionId(connection.Id)
|
||||
.RunTask();
|
||||
|
||||
//
|
||||
var count = connectionStore
|
||||
.Count()
|
||||
.RunTask();
|
||||
|
||||
//
|
||||
Console.WriteLine($"Count After DisCoonected: {count}");
|
||||
// Notify Other Clients Which a Connection Closed ...
|
||||
await Clients.AllExcept(connectionId).SendAsync(XBaseHubAction.ConnectionClosed.GetStringValue(), connectionId);
|
||||
}
|
||||
|
||||
//
|
||||
return base.OnDisconnectedAsync(exception);
|
||||
await base.OnDisconnectedAsync(exception);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Actions ...
|
||||
/// <summary>
|
||||
/// Notify to all Other Clients which a new Connection is established ...
|
||||
/// </summary>
|
||||
/// <param name="connectionId"></param>
|
||||
public Task NotifyNewConnection(string connectionId)
|
||||
{
|
||||
//
|
||||
var actor = Context.User.Identity.Name;
|
||||
var authType = Context.User.Identity.AuthenticationType;
|
||||
var actorRole = Context?.User?.FindFirst("role")?.Value;
|
||||
|
||||
//
|
||||
var pushMessage = new XPushMessage
|
||||
{
|
||||
//
|
||||
Actor = actor,
|
||||
Payload = connectionId,
|
||||
TimeStamp = DateTime.UtcNow,
|
||||
Type = XPushType.System.GetStringValue(),
|
||||
Topic = XPushType.System.GetStringValue(),
|
||||
Action = XBasePushAction.NotifyNewConnection.GetStringValue(),
|
||||
Message = $"a new connection stablished by {connectionId} ...",
|
||||
};
|
||||
|
||||
//
|
||||
Console.WriteLine($"XPushServiceLog => ");
|
||||
Console.WriteLine($"XPushServiceLog => NotifyNewConnection: User: {actor}/Role: {actorRole}/AuthType: {authType}/ConnectionId: {connectionId}/ConnectedAt: {DateTime.UtcNow}");
|
||||
Console.WriteLine($"XPushServiceLog => ");
|
||||
|
||||
//
|
||||
return Clients.Others.SendAsync(
|
||||
XBasePushAction.PushMessage.GetStringValue(),
|
||||
pushMessage
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update Last Seen ...
|
||||
/// </summary>
|
||||
public Task UpdateLastSeen()
|
||||
{
|
||||
var connectionId = Context.ConnectionId;
|
||||
return connectionStore
|
||||
.UpdateLastSeen(connectionId)
|
||||
.ContinueWith(updateLastSeenTask =>
|
||||
{
|
||||
//
|
||||
var updateLastSeen = updateLastSeenTask
|
||||
.RunTask();
|
||||
if (updateLastSeen)
|
||||
{
|
||||
//
|
||||
var updatedConnection = connectionStore
|
||||
.GetByConnectionId(connectionId)
|
||||
.RunTask();
|
||||
|
||||
//
|
||||
var count = connectionStore
|
||||
.Count()
|
||||
.RunTask();
|
||||
|
||||
//
|
||||
Console.WriteLine($"Connection Last Seen Updated: {connectionId}: {updatedConnection.LastSeen}, Connection Count: {count} ...");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// publicly Push a Message to Other Clients ...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public Task PushMessageAsync(XPushMessage message)
|
||||
{
|
||||
//
|
||||
if (message.IsNull())
|
||||
{
|
||||
message = GetPushMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
message.TimeStamp = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
//
|
||||
return Clients.Others.SendAsync(XBasePushAction.PushMessage.GetStringValue(), message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// publicly Push a Message to Other Clients ...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
[Authorize]
|
||||
public Task AuthorizedMessageAsync(XPushMessage message)
|
||||
{
|
||||
//
|
||||
if (message.IsNull())
|
||||
{
|
||||
message = GetPushMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
message.TimeStamp = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
//
|
||||
return Clients.Others.SendAsync(XBasePushAction.PushMessage.GetStringValue(), message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// push message to All connections ...
|
||||
/// </summary>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public Task PushMessageToAll(XPushMessage message)
|
||||
{
|
||||
//
|
||||
// Normalize Message ...
|
||||
if (message.IsNull())
|
||||
{
|
||||
message = GetPushMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
message.TimeStamp = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
//
|
||||
return Clients
|
||||
.All
|
||||
.SendAsync(
|
||||
XBasePushAction.PushMessage.GetStringValue(),
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// push message to specific connection ...
|
||||
/// </summary>
|
||||
/// <param name="connectionId"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public Task PushMessageToConnection(
|
||||
string connectionId,
|
||||
XPushMessage message
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (connectionId.IsNullOrEmpty())
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
//
|
||||
// Normalize Message ...
|
||||
if (message.IsNull())
|
||||
{
|
||||
message = GetPushMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
message.TimeStamp = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
//
|
||||
return Clients
|
||||
.Client(connectionId)
|
||||
.SendAsync(
|
||||
XBasePushAction.PushMessage.GetStringValue(),
|
||||
message
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// push message to specific connections ...
|
||||
/// </summary>
|
||||
/// <param name="connectionIds"></param>
|
||||
/// <param name="message"></param>
|
||||
/// <returns></returns>
|
||||
public Task PushMessageToConnections(
|
||||
IEnumerable<string> connectionIds,
|
||||
XPushMessage message
|
||||
)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
if (!connectionIds.HasChild())
|
||||
{
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
//
|
||||
// Normalize Message ...
|
||||
if (message.IsNull())
|
||||
{
|
||||
message = GetPushMessage();
|
||||
}
|
||||
else
|
||||
{
|
||||
message.TimeStamp = DateTime.UtcNow;
|
||||
}
|
||||
|
||||
//
|
||||
return Clients
|
||||
.Clients(
|
||||
connectionIds
|
||||
.ToList()
|
||||
.AsReadOnly()
|
||||
)
|
||||
.SendAsync(
|
||||
XBasePushAction.PushMessage.GetStringValue(),
|
||||
message
|
||||
);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Protected ...
|
||||
/// <summary>
|
||||
/// retrieve connected user name ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string GetUserName()
|
||||
{
|
||||
return Context?.User?.Identity?.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// retrieve connected user role ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string GetUserRole()
|
||||
{
|
||||
return Context?.User?.FindFirst("role")?.Value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Empty Message ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected XPushMessage GetPushMessage()
|
||||
{
|
||||
//
|
||||
var timeStamp = DateTime.UtcNow;
|
||||
var actor = Context.User.Identity.Name;
|
||||
var connectionId = Context.ConnectionId;
|
||||
|
||||
//
|
||||
var result = new XPushMessage
|
||||
{
|
||||
Actor = actor,
|
||||
TimeStamp = timeStamp,
|
||||
Payload = connectionId,
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// retrieve current connection id ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected string GetConnectionId()
|
||||
{
|
||||
return Context.ConnectionId;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve Connection Model from Context ...
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
protected XPushConnectionDto GetBaseConnection()
|
||||
{
|
||||
//
|
||||
var connectionId = Context.ConnectionId;
|
||||
var userName = Context.User.Identity.Name;
|
||||
var authenticationType = Context.User.Identity.AuthenticationType;
|
||||
|
||||
//
|
||||
var httpContext = Context.GetHttpContext();
|
||||
var deviceJson = httpContext.Request.Query["Option"].ToString();
|
||||
var device = deviceJson.FromJSON<XDeviceDto>();
|
||||
|
||||
//
|
||||
var result = new XPushConnectionDto
|
||||
{
|
||||
User = userName,
|
||||
Device = device,
|
||||
Id = connectionId,
|
||||
LastSeen = DateTime.UtcNow
|
||||
};
|
||||
|
||||
//
|
||||
return result;
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Private ...
|
||||
#region Actions ...
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
using System;
|
||||
using System.Reactive.Subjects;
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
using xPushService.Configurations;
|
||||
using xPushService.Models;
|
||||
using xPushService.Policies;
|
||||
|
||||
namespace xPushService.Base {
|
||||
// TODO: Complete this ...
|
||||
public class XBaseHubClient {
|
||||
//
|
||||
#region Props ...
|
||||
//
|
||||
// private string CONNECTION_ID;
|
||||
// private HubConnection HUB_CONNECTION;
|
||||
// private IDisposable INTERVAL_SUBSCRIPTION;
|
||||
// private XPushServiceConnectionRetryPolicy HUB_CONNECTION_POLICY;
|
||||
|
||||
//
|
||||
public Subject<XPushMessage> MessageReceived = new Subject<XPushMessage> ();
|
||||
public Subject<XPushMessage> UserMessageReceived = new Subject<XPushMessage> ();
|
||||
public Subject<XPushMessage> SystemMessageReceived = new Subject<XPushMessage> ();
|
||||
|
||||
//
|
||||
public Subject<Exception> OnClose = new Subject<Exception> ();
|
||||
public Subject<string> OnReconnected = new Subject<string> ();
|
||||
public Subject<Exception> OnReconnecting = new Subject<Exception> ();
|
||||
|
||||
/// <summary>
|
||||
/// readonly connection id ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
// public string ConnectionId {
|
||||
// get {
|
||||
// return this.CONNECTION_ID;
|
||||
// }
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// readonly connection object ...
|
||||
/// </summary>
|
||||
/// <value></value>
|
||||
// public HubConnection Connection {
|
||||
// get {
|
||||
// return this.HUB_CONNECTION;
|
||||
// }
|
||||
// }
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Constructor ...
|
||||
public XBaseHubClient (
|
||||
XPushServiceConfiguration config
|
||||
) {
|
||||
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Abstract ...
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Protected ...
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Actions ...
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region IXAuthorizedPushActions ...
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region IXUserPushActions ...
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region IXGroupsPushActions ...
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Private ...
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
+36
-804
@@ -1,834 +1,66 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using xCommons.Extensions;
|
||||
using xExceptions.Constants;
|
||||
using xModels.Dtos;
|
||||
using xPushService.Constants;
|
||||
using xPushService.Extensions;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using xPushService.Interfaces;
|
||||
using xPushService.Models;
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using xPushService.Constants;
|
||||
using xCommons.Extensions;
|
||||
|
||||
namespace xPushService.Base {
|
||||
public abstract class XBaseWebRTCHub : XBaseHub {
|
||||
namespace xPushService.Base
|
||||
{
|
||||
public abstract class XBaseWebRTCHub : XBaseHub, IXBaseWebRTCHub
|
||||
{
|
||||
//
|
||||
#region Props ...
|
||||
protected readonly IXWebRTCConnectionStore webRTCConnectionStore;
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Constructor ...
|
||||
public XBaseWebRTCHub (
|
||||
IXPushGroupStore groupStore,
|
||||
IXPushConnectionStore connectionStore,
|
||||
IXWebRTCConnectionStore webRTCConnectionStore
|
||||
) : base (groupStore, connectionStore) {
|
||||
this.webRTCConnectionStore = webRTCConnectionStore;
|
||||
}
|
||||
protected XBaseWebRTCHub(
|
||||
ILogger<XBaseHub> logger
|
||||
) : base(logger)
|
||||
{ }
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Overrides ...
|
||||
public override Task OnConnectedAsync () {
|
||||
return base.OnConnectedAsync ();
|
||||
}
|
||||
|
||||
public override Task OnDisconnectedAsync (Exception exception) {
|
||||
// //
|
||||
// var connectionId = GetConnectionId ();
|
||||
|
||||
// //
|
||||
// // Find Connections Active Calls ...
|
||||
// var activeConnections = webRTCConnectionStore
|
||||
// .FindMany (c => c.CallerConnectionId
|
||||
// .ToNormalString () == connectionId
|
||||
// .ToNormalString () ||
|
||||
// c.IsInCallees (connectionId)
|
||||
// )
|
||||
// .RunTask ();
|
||||
|
||||
// //
|
||||
// if (activeConnections.HasChild ()) {
|
||||
// activeConnections
|
||||
// .ToList ()
|
||||
// .ForEach (c => {
|
||||
// //
|
||||
// CancelCall (
|
||||
// cancellerConnectionId: connectionId,
|
||||
// reason: XCallEndReason.Disconnected,
|
||||
// request: c
|
||||
// )
|
||||
// .RunTask ();
|
||||
// });
|
||||
// }
|
||||
|
||||
//
|
||||
return base.OnDisconnectedAsync (exception);
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Actions ...
|
||||
#region WebRTCActions ...
|
||||
/// <summary>
|
||||
/// Send PreOffer Call Request ...
|
||||
/// Sending WebRTC Offer To Specified Connection ...
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="connectionId"></param>
|
||||
/// <param name="device"></param>
|
||||
/// <param name="offer"></param>
|
||||
/// <param name="to"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> RequestCall (
|
||||
XCallType type,
|
||||
string connectionId,
|
||||
XDeviceDto device
|
||||
) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (type == XCallType.None || connectionId.IsNullOrEmpty ()) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
// Check Connection Exists ...
|
||||
var isConnectionExists = connectionStore
|
||||
.IsExistsConnectionId (connectionId)
|
||||
.RunTask ();
|
||||
if (!isConnectionExists) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
// retrieve connection object ...
|
||||
var request = GetWebRTCConnection (
|
||||
calleeDevice: device,
|
||||
connectionType: type,
|
||||
calleeConnectionId: connectionId
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
// Add Connection to Store ...
|
||||
AddOrUpdateWebRTCConnection (request)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
try {
|
||||
//
|
||||
Clients
|
||||
.Clients (
|
||||
request
|
||||
.GetReceivers ()
|
||||
)
|
||||
.SendAsync (
|
||||
XWebRTCAction.RequestCall.GetStringValue (),
|
||||
request
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
} catch { }
|
||||
|
||||
//
|
||||
return Task.FromResult (false);
|
||||
public async Task Offer(string offer, string to)
|
||||
{
|
||||
await Clients.Client(to).SendAsync(XWebRTCAction.Offer.GetStringValue(), offer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send PreOffer Call Request ...
|
||||
/// Sending WebRTC Answer to Specified Connection ...
|
||||
/// </summary>
|
||||
/// <param name="type"></param>
|
||||
/// <param name="user"></param>
|
||||
/// <param name="device"></param>
|
||||
/// <param name="answer"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> RequestUserCall (
|
||||
XCallType type,
|
||||
string user,
|
||||
XDeviceDto device
|
||||
) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (type == XCallType.None || user.IsNullOrEmpty ()) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
// Check Connection Exists ...
|
||||
var isConnectionExists = connectionStore
|
||||
.IsExistsUser (user)
|
||||
.RunTask ();
|
||||
if (!isConnectionExists) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
// retrieve connection object ...
|
||||
var request = GetUserWebRTCConnection (
|
||||
calleeDevice: device,
|
||||
connectionType: type,
|
||||
calleeUser: user
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
// Add Connection to Store ...
|
||||
AddOrUpdateWebRTCConnection (request)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
try {
|
||||
//
|
||||
Clients
|
||||
.Clients (
|
||||
request
|
||||
.GetReceivers ()
|
||||
)
|
||||
.SendAsync (
|
||||
XWebRTCAction.RequestCall.GetStringValue (),
|
||||
request
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
} catch { }
|
||||
|
||||
//
|
||||
return Task.FromResult (false);
|
||||
public async Task Answer(string answer)
|
||||
{
|
||||
await Clients.All.SendAsync(XWebRTCAction.Answer.GetStringValue(), answer, Context.ConnectionId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cancel or End Requested Call ...
|
||||
/// Sending WebRTC Candidate to Specified Connecton ...
|
||||
/// </summary>
|
||||
/// <param name="candidate"></param>
|
||||
/// <param name="to"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> CancelCall (
|
||||
string cancellerConnectionId,
|
||||
XCallEndReason reason,
|
||||
XWebRTCConnectionDto request) {
|
||||
public async Task Candidate(string candidate, string to)
|
||||
{
|
||||
//
|
||||
// Validate Args ...
|
||||
var isValid = IsWebRTCConnectionsExists (request)
|
||||
.RunTask ();
|
||||
if (!isValid) {
|
||||
return Task.FromResult (false);
|
||||
string actionName = XWebRTCAction.Candidate.GetStringValue();
|
||||
if (!string.IsNullOrEmpty(to))
|
||||
{
|
||||
await Clients.Client(to).SendAsync(actionName, candidate, Context.ConnectionId);
|
||||
}
|
||||
|
||||
//
|
||||
// Check if i am Caller ...
|
||||
var isCancellerCaller = request
|
||||
.IsCaller (cancellerConnectionId);
|
||||
var isCancellerInCallees = request
|
||||
.IsInCallees (cancellerConnectionId);
|
||||
|
||||
//
|
||||
if (isCancellerCaller) {
|
||||
//
|
||||
request.Callees.ToList ().ForEach (callee => {
|
||||
//
|
||||
callee.EndReason = reason;
|
||||
callee.EndTime = DateTime.UtcNow;
|
||||
});
|
||||
|
||||
//
|
||||
// Remove Connection From Store ...
|
||||
webRTCConnectionStore
|
||||
.Remove (request)
|
||||
.RunTask ();
|
||||
} else if (isCancellerInCallees) {
|
||||
//
|
||||
var canceller = request.GetCallee (cancellerConnectionId);
|
||||
if (canceller.IsNull ()) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
var updatedCanceller = canceller;
|
||||
updatedCanceller.EndReason = reason;
|
||||
updatedCanceller.EndTime = DateTime.UtcNow;
|
||||
|
||||
//
|
||||
request.Callees = request.Callees
|
||||
.Update (canceller, updatedCanceller);
|
||||
|
||||
//
|
||||
// Remove connection from Store if all callees end calls ...
|
||||
var canRemoveConnection = request.Callees.All (c => !c.EndTime.IsNull () && !c.EndReason.IsNull ());
|
||||
if (canRemoveConnection) {
|
||||
webRTCConnectionStore
|
||||
.Remove (request)
|
||||
.RunTask ();
|
||||
} else {
|
||||
webRTCConnectionStore
|
||||
.Update (request)
|
||||
.RunTask ();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
try {
|
||||
//
|
||||
Clients
|
||||
.Clients (
|
||||
request.GetReceivers ()
|
||||
)
|
||||
.SendAsync (
|
||||
XWebRTCAction.CancelCall.GetStringValue (),
|
||||
request
|
||||
);
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
} catch {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// end a call request ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> RejectCall (
|
||||
string rejecterConnectionId,
|
||||
XWebRTCConnectionDto request
|
||||
) {
|
||||
//
|
||||
// Validate Args ...
|
||||
var isValid = IsWebRTCConnectionsExists (request)
|
||||
.RunTask ();
|
||||
var isRejecterInCallees = request
|
||||
.IsInCallees (rejecterConnectionId);
|
||||
if (!isValid ||
|
||||
!isRejecterInCallees ||
|
||||
rejecterConnectionId.IsNullOrEmpty ()
|
||||
) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
// Find Rejecter and Push Reject to it ...
|
||||
var rejecter = request
|
||||
.GetCallee (rejecterConnectionId);
|
||||
if (rejecter.IsNull ()) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
// Update request Callees ...
|
||||
var updatedRejecter = rejecter;
|
||||
updatedRejecter.EndTime = DateTime.UtcNow;
|
||||
updatedRejecter.EndReason = XCallEndReason.Reject;
|
||||
request.Callees = request.Callees
|
||||
.Update (rejecter, updatedRejecter);
|
||||
|
||||
//
|
||||
// Check if Only one Callee and he Reject, Remove connection From Store,
|
||||
// otherwise Update connection ...
|
||||
var canRemoveConnection = request
|
||||
.Callees.Count () == 1 && request.Callees
|
||||
.All (c => c.ConnectionId
|
||||
.ToNormalString () == rejecterConnectionId
|
||||
.ToNormalString ()
|
||||
);
|
||||
if (canRemoveConnection) {
|
||||
webRTCConnectionStore
|
||||
.Remove (request)
|
||||
.RunTask ();
|
||||
}
|
||||
|
||||
//
|
||||
// Prepare Receivers ...
|
||||
var receivers = new List<string> () {
|
||||
request.CallerConnectionId,
|
||||
rejecterConnectionId
|
||||
}
|
||||
.AsReadOnly ();
|
||||
|
||||
//
|
||||
try {
|
||||
//
|
||||
Clients
|
||||
.Clients (receivers)
|
||||
.SendAsync (
|
||||
XWebRTCAction.RejectCall.GetStringValue (),
|
||||
request
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
} catch { }
|
||||
|
||||
//
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// answer a call request ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> AcceptCall (
|
||||
string accepterConnectionId,
|
||||
XWebRTCConnectionDto request
|
||||
) {
|
||||
//
|
||||
// Validate Args ...
|
||||
var isValid = IsWebRTCConnectionsExists (request)
|
||||
.RunTask ();
|
||||
var isAccepterInCallees = request
|
||||
.IsInCallees (accepterConnectionId);
|
||||
if (!isValid ||
|
||||
!isAccepterInCallees ||
|
||||
accepterConnectionId.IsNullOrEmpty ()
|
||||
) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
// Add Or Update ...
|
||||
AddOrUpdateWebRTCConnection (request)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
// prepare recievers ...
|
||||
var receivers = new List<string> () {
|
||||
request.CallerConnectionId,
|
||||
accepterConnectionId,
|
||||
}
|
||||
.AsReadOnly ();
|
||||
|
||||
//
|
||||
try {
|
||||
//
|
||||
Clients
|
||||
.Clients (receivers)
|
||||
.SendAsync (
|
||||
XWebRTCAction.AcceptCall.GetStringValue (),
|
||||
request
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
} catch {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region WebRTC Signaling ...
|
||||
/// <summary>
|
||||
/// Send WebRTC Offer ...
|
||||
/// </summary>
|
||||
/// <param name="signal"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> WebRTCOffer (
|
||||
XWebRTCSignalDto signal,
|
||||
XWebRTCConnectionDto request
|
||||
) {
|
||||
//
|
||||
if (
|
||||
signal.IsNull () ||
|
||||
signal.Offer.IsNull () ||
|
||||
!IsValidWebRTCConnection (request)
|
||||
) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
var connectionId = GetConnectionId ();
|
||||
var offerRecievers = request
|
||||
.GetReceivers ()
|
||||
.Where (r => r.ToNormalString () != connectionId.ToNormalString ())
|
||||
.ToList ()
|
||||
.AsReadOnly ();
|
||||
|
||||
//
|
||||
try {
|
||||
//
|
||||
Clients
|
||||
.Clients (offerRecievers)
|
||||
.SendAsync (
|
||||
XWebRTCAction.WebRTCOffer.GetStringValue (),
|
||||
signal,
|
||||
request
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
} catch {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send WebRTC Answer ...
|
||||
/// </summary>
|
||||
/// <param name="signal"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> WebRTCAnswer (
|
||||
XWebRTCSignalDto signal,
|
||||
XWebRTCConnectionDto request
|
||||
) {
|
||||
//
|
||||
if (
|
||||
signal.IsNull () ||
|
||||
signal.Offer.IsNull () ||
|
||||
signal.Answer.IsNull () ||
|
||||
!IsValidWebRTCConnection (request)
|
||||
) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
var connectionId = GetConnectionId ();
|
||||
var answerRecievers = request
|
||||
.GetReceivers ()
|
||||
.Where (r => r.ToNormalString () != connectionId.ToNormalString ())
|
||||
.ToList ()
|
||||
.AsReadOnly ();
|
||||
|
||||
//
|
||||
try {
|
||||
//
|
||||
Clients
|
||||
.Clients (answerRecievers)
|
||||
.SendAsync (
|
||||
XWebRTCAction.WebRTCAnswer.GetStringValue (),
|
||||
signal,
|
||||
request
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
} catch {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Send WebRTC ICE Candidates ...
|
||||
/// </summary>
|
||||
/// <param name="signal"></param>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
public Task<bool> WebRTCICECandidate (
|
||||
XWebRTCSignalDto signal,
|
||||
XWebRTCConnectionDto request
|
||||
) {
|
||||
//
|
||||
if (
|
||||
signal.IsNull () ||
|
||||
signal.Offer.IsNull () ||
|
||||
signal.Answer.IsNull () ||
|
||||
!signal.Cadidates.HasChild () ||
|
||||
!IsValidWebRTCConnection (request)
|
||||
) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
var connectionId = GetConnectionId ();
|
||||
var candidatesRecievers = request
|
||||
.GetReceivers ()
|
||||
.Where (r => r.ToNormalString () != connectionId.ToNormalString ())
|
||||
.ToList ()
|
||||
.AsReadOnly ();
|
||||
|
||||
//
|
||||
try {
|
||||
//
|
||||
Clients
|
||||
.Clients (candidatesRecievers)
|
||||
.SendAsync (
|
||||
XWebRTCAction.WebRTCICECandidate.GetStringValue (),
|
||||
signal,
|
||||
request
|
||||
)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
} catch {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
//
|
||||
#region Protected ...
|
||||
/// <summary>
|
||||
/// create first time WebRTC connection by user name ...
|
||||
/// </summary>
|
||||
/// <param name="connectionType"></param>
|
||||
/// <param name="calleeUser"></param>
|
||||
/// <param name="calleeDevice"></param>
|
||||
/// <returns></returns>
|
||||
protected Task<XWebRTCConnectionDto> GetUserWebRTCConnection (
|
||||
XCallType connectionType,
|
||||
string calleeUser,
|
||||
XDeviceDto calleeDevice
|
||||
) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (
|
||||
calleeDevice.IsNull () ||
|
||||
connectionType == XCallType.None ||
|
||||
calleeUser.IsNullOrEmpty ()
|
||||
) {
|
||||
throw XException.InvalidArgs.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
var id = Guid.NewGuid ().ToString ();
|
||||
|
||||
//
|
||||
var httpContext = Context.GetHttpContext ();
|
||||
var deviceJson = httpContext.Request.Query["Option"].ToString ();
|
||||
|
||||
//
|
||||
// Retrieve Caller Info ...
|
||||
var callerConnectionId = Context.ConnectionId;
|
||||
var callerUserName = Context?.User?.Identity?.Name;
|
||||
var callerDevice = deviceJson.FromJSON<XDeviceDto> ();
|
||||
|
||||
//
|
||||
// Retrieve Connection ...
|
||||
var calleeConnection = connectionStore
|
||||
.FindOne (c => c.User.ToNormalString () == calleeUser.ToNormalString ())
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
var result = new XWebRTCConnectionDto {
|
||||
//
|
||||
Id = id,
|
||||
//
|
||||
Payload = null,
|
||||
Type = connectionType,
|
||||
//
|
||||
RequestTime = DateTime.UtcNow,
|
||||
//
|
||||
CallerUser = callerUserName,
|
||||
CallerDevice = callerDevice,
|
||||
CallerConnectionId = callerConnectionId,
|
||||
//
|
||||
Callees = new List<XWebRTCCalleeDto> {
|
||||
new XWebRTCCalleeDto {
|
||||
Device = calleeDevice,
|
||||
User = calleeConnection.User,
|
||||
ConnectionId = calleeConnection.Id,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
return Task.FromResult (result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// create first time WebRTC connection ...
|
||||
/// </summary>
|
||||
/// <param name="connectionType"></param>
|
||||
/// <param name="calleeConnectionId"></param>
|
||||
/// <param name="calleeDevice"></param>
|
||||
/// <returns></returns>
|
||||
protected Task<XWebRTCConnectionDto> GetWebRTCConnection (
|
||||
XCallType connectionType,
|
||||
string calleeConnectionId,
|
||||
XDeviceDto calleeDevice
|
||||
) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (
|
||||
calleeDevice.IsNull () ||
|
||||
connectionType == XCallType.None ||
|
||||
calleeConnectionId.IsNullOrEmpty ()
|
||||
) {
|
||||
throw XException.InvalidArgs.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
var id = Guid.NewGuid ().ToString ();
|
||||
|
||||
//
|
||||
var httpContext = Context.GetHttpContext ();
|
||||
var deviceJson = httpContext.Request.Query["Option"].ToString ();
|
||||
|
||||
//
|
||||
// Retrieve Caller Info ...
|
||||
var callerConnectionId = Context.ConnectionId;
|
||||
var callerUserName = Context?.User?.Identity?.Name;
|
||||
var callerDevice = deviceJson.FromJSON<XDeviceDto> ();
|
||||
|
||||
//
|
||||
// Retrieve Connection ...
|
||||
var calleeConnection = connectionStore
|
||||
.GetByConnectionId (calleeConnectionId)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
var result = new XWebRTCConnectionDto {
|
||||
//
|
||||
Id = id,
|
||||
//
|
||||
Payload = null,
|
||||
Type = connectionType,
|
||||
//
|
||||
RequestTime = DateTime.UtcNow,
|
||||
//
|
||||
CallerUser = callerUserName,
|
||||
CallerDevice = callerDevice,
|
||||
CallerConnectionId = callerConnectionId,
|
||||
//
|
||||
Callees = new List<XWebRTCCalleeDto> {
|
||||
new XWebRTCCalleeDto {
|
||||
Device = calleeDevice,
|
||||
User = calleeConnection.User,
|
||||
ConnectionId = calleeConnectionId,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
return Task.FromResult (result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check i am caller or not ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
protected bool AmICaller (XWebRTCConnectionDto request) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (!request.IsValid () ||
|
||||
!IsValidWebRTCConnection (request)
|
||||
) {
|
||||
throw XException.InvalidArgs.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
var result = request.IsCaller (GetConnectionId ());
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check i am callee or not ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
protected bool AmICallee (XWebRTCConnectionDto request) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (!request.IsValid () ||
|
||||
!IsValidWebRTCConnection (request)) {
|
||||
throw XException.InvalidArgs.ToException ();
|
||||
}
|
||||
|
||||
//
|
||||
var result = request.IsInCallees (GetConnectionId ());
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// validate a web rtc connection ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
protected bool IsValidWebRTCConnection (XWebRTCConnectionDto request) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (
|
||||
request.IsNull () ||
|
||||
!request.IsValid () ||
|
||||
!request.Callees.HasChild () ||
|
||||
request.Type == XCallType.None ||
|
||||
request.CallerConnectionId.IsNullOrEmpty ()
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// check bot Caller and Callee Connections Exists ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
protected Task<bool> IsWebRTCConnectionsExists (XWebRTCConnectionDto request) {
|
||||
//
|
||||
// Validate Args ...
|
||||
if (!IsValidWebRTCConnection (request)) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
var isCallerConnectionExists = connectionStore
|
||||
.IsExistsConnectionId (request.CallerConnectionId)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
var isCalleesConnectionExists = !request.Callees.HasChild () ? true :
|
||||
Task.WhenAll (request.Callees.Select (callee => connectionStore
|
||||
.IsExistsConnectionId (callee.ConnectionId)))
|
||||
.ContinueWith (allTasks => {
|
||||
//
|
||||
var allResults = allTasks
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
return allResults.All (r => r == true);
|
||||
})
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
if (!isCallerConnectionExists || !isCalleesConnectionExists) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
return Task.FromResult (true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add or Update a WebRTCConnection To/In Store ...
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <returns></returns>
|
||||
protected Task<bool> AddOrUpdateWebRTCConnection (XWebRTCConnectionDto request) {
|
||||
//
|
||||
if (!request.IsValid () ||
|
||||
request.Id.IsNullOrEmpty ()
|
||||
) {
|
||||
return Task.FromResult (false);
|
||||
}
|
||||
|
||||
//
|
||||
// Check Exists or not ...
|
||||
var isWebRTCConnectionExists = webRTCConnectionStore
|
||||
.IsExistsByKey (request.Id)
|
||||
.RunTask ();
|
||||
|
||||
//
|
||||
// Act based on existance ...
|
||||
if (!isWebRTCConnectionExists) {
|
||||
return webRTCConnectionStore.Add (request);
|
||||
} else {
|
||||
//
|
||||
var updated = webRTCConnectionStore.Update (request)
|
||||
.RunTask ();
|
||||
var isUpdate = !updated.IsNull ();
|
||||
|
||||
//
|
||||
return Task.FromResult (isUpdate);
|
||||
else
|
||||
{
|
||||
await Clients.All.SendAsync(actionName, candidate, Context.ConnectionId);
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
Reference in New Issue
Block a user