Backup and Clean Push Service and implement new Structure of Push Service ...

This commit is contained in:
2025-11-14 16:40:45 +03:30
parent cfcb2d12b4
commit 3bd4b8d562
40 changed files with 333 additions and 2560 deletions
+20 -361
View File
@@ -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
}
}
-87
View File
@@ -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
View File
@@ -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
@@ -6,24 +6,12 @@ namespace xPushService.Configurations {
/// <value>string</value>
public string BaseRoute { get; set; }
/// <summary>
/// main action of push messages ...
/// </summary>
/// <value></value>
public string PushMessageAction { get; set; }
/// <summary>
/// determines log level of signalR ...
/// </summary>
/// <value></value>
public object ConnectionLogLevel { get; set; }
/// <summary>
/// when a client connected it's going to update last seen of a client by this interval ...
/// </summary>
/// <value></value>
public int UpdateLastSeenInterval { get; set; }
/// <summary>
/// when client disconnected it's automatically try to reconnect, this
/// determines max number of try to connect ...
-9
View File
@@ -1,9 +0,0 @@
namespace xPushService.Constants {
public enum XCallEndReason {
End,
Missed,
Reject,
Canceled,
Disconnected
}
}
-11
View File
@@ -1,11 +0,0 @@
namespace xPushService.Constants {
public enum XCallType {
None,
Chat,
AudioCall,
VideoCall,
DesktopShare,
AudioConference,
VideoConference,
}
}
+34
View File
@@ -0,0 +1,34 @@
using xExceptions.Attributes;
namespace xPushService.Constants
{
public enum XBaseHubAction
{
/// <summary>
/// new Connection Join ...
/// </summary>
[StringValue("NewConnection")]
NewConnection,
/// <summary>
/// an Exists Connection Closed ...
/// </summary>
[StringValue("ConnectionClosed")]
ConnectionClosed,
}
/// <summary>
/// All Actions in WebRTC Hubs ...
/// </summary>
public enum XWebRTCAction
{
//
[StringValue("Offer")]
Offer,
[StringValue("Answer")]
Answer,
[StringValue("Candidate")]
Candidate,
}
}
-32
View File
@@ -1,32 +0,0 @@
using xExceptions.Attributes;
namespace xPushService.Constants {
/// <summary>
/// Determines Push Notification Types
/// </summary>
public enum XPushType {
/// System Type Notifications Relate Only to System
[StringValue("system")]
System,
/// User Specific Types Of Push Notifications
[StringValue("user")]
User
}
/// <summary>
/// Base Push Actions ...
/// </summary>
public enum XBasePushAction {
[StringValue ("PushMessageAsync")]
PushMessage,
[StringValue ("UserMessageAsync")]
UserMessage,
[StringValue ("AdminMessageAsync")]
AdminMessage,
[StringValue("AuthorizedMessageAsync")]
AuthorizedMessage,
[StringValue("NotifyNewConnection")]
NotifyNewConnection
}
}
-32
View File
@@ -1,32 +0,0 @@
using xExceptions.Attributes;
namespace xPushService.Constants {
public enum XWebRTCAction {
//
[StringValue ("RequestCall")]
RequestCall,
[StringValue ("RequestUserCall")]
RequestUserCall,
//
[StringValue ("CancelCall")]
CancelCall,
[StringValue ("RejectCall")]
RejectCall,
[StringValue ("AcceptCall")]
AcceptCall,
//
[StringValue ("WebRTCOffer")]
WebRTCOffer,
[StringValue ("WebRTCAnswer")]
WebRTCAnswer,
[StringValue ("WebRTCICECandidate")]
WebRTCICECandidate,
}
}
+3 -40
View File
@@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using Microsoft.AspNetCore.Builder;
@@ -15,9 +14,7 @@ using xExceptions.Constants;
using xPushService.Configurations;
using xPushService.Constants;
using xPushService.Helpers;
using xPushService.Interfaces;
using xPushService.Providers;
using xPushService.Store;
namespace xPushService.DI
{
@@ -70,6 +67,7 @@ namespace xPushService.DI
ServiceLifetime lifeTime = ServiceLifetime.Singleton
)
{
//
AddPushService(
services,
config.GetXPushServiceConfiguration(),
@@ -88,6 +86,7 @@ namespace xPushService.DI
ServiceLifetime lifeTime = ServiceLifetime.Singleton
)
{
//
AddPushService(
services,
config,
@@ -159,7 +158,7 @@ namespace xPushService.DI
helper.GetHubs().ForEach(hubDescriptor =>
{
//
var hubRoute = config.BaseRoute + "/" + hubDescriptor.Route; // Path.Combine (config.BaseRoute, hubDescriptor.Route);
var hubRoute = config.BaseRoute + "/" + hubDescriptor.Route;
hubRoutes.Add(hubRoute);
Console.WriteLine($"XPushService HubRoute: {hubRoute}");
@@ -253,42 +252,6 @@ namespace xPushService.DI
// Register XPushService Configuration ...
services.AddSingleton<XPushServiceConfiguration>(config);
//
#region Try to Register Stores ...
//
var groupStore = services.GetRegisteredService<IXPushGroupStore>();
if (groupStore.IsNull())
{
//
Log($"there is no provided PushGroupStore, try to register XPushGroupInMemoryStore ...");
var storeEvents = services.GetRegisteredService<IXPushGroupStoreEvents>();
groupStore = new XPushGroupInMemoryStore(storeEvents);
services.AddSingleton<IXPushGroupStore>(groupStore);
}
//
var connectionStore = services.GetRegisteredService<IXPushConnectionStore>();
if (connectionStore.IsNull())
{
//
Log($"there is no provided XPushConnectionStore, try to register XPushConnectionInMemoryStore ...");
var storeEvents = services.GetRegisteredService<IXPushConnectionStoreEvents>();
connectionStore = new XPushConnectionInMemoryStore(storeEvents);
services.AddSingleton<IXPushConnectionStore>(connectionStore);
}
//
var webRtcConnectionStore = services.GetRegisteredService<IXWebRTCConnectionStore>();
if (webRtcConnectionStore.IsNull())
{
//
Log($"there is no provided XWebRTCConnectionStore, try to register XWebRTCConnectionInMemoryStore ...");
var storeEvents = services.GetRegisteredService<IXWebRTCConnectionStoreEvents>();
webRtcConnectionStore = new XWebRTCConnectionInMemoryStore(storeEvents);
services.AddSingleton<IXWebRTCConnectionStore>(webRtcConnectionStore);
}
#endregion
//
// Register SignalR ...
var builder = services.AddSignalR();
-9
View File
@@ -1,9 +0,0 @@
using xModels.Base;
using xPushService.Interfaces;
using xPushService.Models;
namespace xPushService.Events
{
public class XPushConnectionStoreEvents : XBaseStoreEvent<XPushConnectionDto, string>, IXPushConnectionStoreEvents
{ }
}
-9
View File
@@ -1,9 +0,0 @@
using xModels.Base;
using xPushService.Interfaces;
using xPushService.Models;
namespace xPushService.Events
{
public class XPushGroupStoreEvents : XBaseStoreEvent<XPushGroupDto, string>, IXPushGroupStoreEvents
{ }
}
-9
View File
@@ -1,9 +0,0 @@
using xModels.Base;
using xPushService.Interfaces;
using xPushService.Models;
namespace xPushService.Events
{
public class XWebRTCConnectionStoreEvents : XBaseStoreEvent<XWebRTCConnectionDto, string>, IXWebRTCConnectionStoreEvents
{ }
}
+199
View File
@@ -0,0 +1,199 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.SignalR;
using xCommons.Constants;
using xCommons.Extensions;
using xCommons.Helpers;
using xIdentityModels.Constants;
using xPushService.Models;
namespace xPushService.Extensions
{
public static class ClaimsPrincipalExtensions
{
/// <summary>
/// Generate User Info based on HubCallerContext ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static XHubUserInfo GetUserInfo(this HubCallerContext source)
{
//
XHubUserInfo result = null;
//
if (source.IsNull() || source.User.IsNull() || !source.User.Claims.HasChild())
{
return result;
}
//
result = new XHubUserInfo
{
UserId = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.UserId)?.Value ?? "",
UserName = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.UserName)?.Value ?? "",
FirstName = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.FirstName)?.Value ?? "",
LastName = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.LastName)?.Value ?? "",
Picture = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.Picture)?.Value ?? "",
Email = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.Email)?.Value ?? null,
PhoneNumber = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.PhoneNumber)?.Value ?? null,
};
//
#region Handle Gender ...
var genders = ObjectHelper.ToEnumerableKeys<XGender>();
var genderStr = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.Gender).Value ?? null;
if (genderStr.IsNullOrEmpty())
{
result.Gender = XGender.Male;
}
else
{
result.Gender = genderStr.GetValue<XGender>();
}
#endregion
//
#region Handle IsBanned ...
var isBannedStr = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.IsBanned).Value ?? null;
if (isBannedStr.IsNullOrEmpty())
{
result.IsBanned = false;
}
else
{
//
var isBanned = false;
Boolean.TryParse(isBannedStr, out isBanned);
//
result.IsBanned = isBanned;
}
#endregion
//
#region Handle IsEnabled ...
var isEnabledStr = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.IsEnabled).Value ?? null;
if (isEnabledStr.IsNullOrEmpty())
{
result.IsEnabled = false;
}
else
{
//
var isEnabled = false;
Boolean.TryParse(isEnabledStr, out isEnabled);
//
result.IsEnabled = isEnabled;
}
#endregion
//
#region Handle Email Confirmed ...
var emailConfirmedStr = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.EmailVerified).Value ?? null;
if (emailConfirmedStr.IsNullOrEmpty())
{
result.EmailConfirmed = false;
}
else
{
//
var emailConfirmed = false;
Boolean.TryParse(emailConfirmedStr, out emailConfirmed);
//
result.EmailConfirmed = emailConfirmed;
}
#endregion
//
#region Handle PhoneNumber Confirmed ...
var phoneNumberConfirmedStr = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.PhoneNumberVerified).Value ?? null;
if (phoneNumberConfirmedStr.IsNullOrEmpty())
{
result.PhoneNumberConfirmed = false;
}
else
{
//
var phoneNumberConfirmed = false;
Boolean.TryParse(phoneNumberConfirmedStr, out phoneNumberConfirmed);
//
result.PhoneNumberConfirmed = phoneNumberConfirmed;
}
#endregion
//
#region Handle ExpiredOn ...
var expiredOnStr = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.ExpiredOn).Value ?? null;
if (expiredOnStr.IsNullOrEmpty())
{
result.ExpiredOn = null;
}
else
{
//
long expiredOn = 0;
long.TryParse(expiredOnStr, out expiredOn);
//
result.ExpiredOn = expiredOn;
}
#endregion
//
#region Handle AuthenticatedOn ...
var authenticatedOnStr = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.AuthenticatedOn).Value ?? null;
if (authenticatedOnStr.IsNullOrEmpty())
{
result.AuthenticatedOn = null;
}
else
{
//
long authenticatedOn = 0;
long.TryParse(authenticatedOnStr, out authenticatedOn);
//
result.AuthenticatedOn = authenticatedOn;
}
#endregion
//
#region Handle BrithDate ...
var brithDateStr = source.User.Claims.FirstOrDefault(c => c.Type == XCustomClaims.BrithDate)?.Value ?? "";
if (brithDateStr.IsNullOrEmpty())
{
// BrithDate = null;
}
else
{
//
DateTime bDate;
DateTime.TryParse(brithDateStr, out bDate);
//
result.BrithDate = bDate;
}
#endregion
//
result.Issuers = source.User.Claims.Where(c => c.Type == XCustomClaims.Issuer)?
.Select(c => c.Value) ?? new HashSet<string>();
result.Audiences = source.User.Claims.Where(c => c.Type == XCustomClaims.Audience)?
.Select(c => c.Value) ?? new HashSet<string>();
result.ClientIds = source.User.Claims.Where(c => c.Type == XCustomClaims.ClientId)?
.Select(c => c.Value) ?? new HashSet<string>();
result.Scopes = source.User.Claims.Where(c => c.Type == XCustomClaims.Scope)?
.Select(c => c.Value) ?? new HashSet<string>();
result.Roles = source.User.Claims.Where(c => c.Type == XCustomClaims.Role)?
.Select(c => c.Value) ?? new HashSet<string>();
//
return result;
}
}
}
-157
View File
@@ -1,157 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using xCommons.Extensions;
using xPushService.Models;
namespace xPushService.Extensions {
public static class XWebRTCConnectionExtensions {
/// <summary>
/// Validate Connection ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static bool IsValid (this XWebRTCConnectionDto source) {
//
var result = false;
result = !source
.IsNull () && !source.CallerConnectionId
.IsNullOrEmpty () && (
source.Callees
.HasChild () ? source.Callees
.All (callee => !callee.ConnectionId.IsNullOrDefault ()) :
true
);
//
return result;
}
/// <summary>
/// Check a ConnectionId is Caller of a connection ...
/// </summary>
/// <param name="source"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
public static bool IsCaller (
this XWebRTCConnectionDto source,
string connectionId
) {
//
var result = false;
//
// Validate Args ...
if (!source.IsValid () ||
connectionId.IsNullOrEmpty ()
) {
return result;
}
//
result = connectionId
.ToNormalString () == source.CallerConnectionId
.ToNormalString ();
return result;
}
/// <summary>
/// Check a ConnectionId is in Callees of a connection ...
/// </summary>
/// <param name="source"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
public static bool IsInCallees (
this XWebRTCConnectionDto source,
string connectionId
) {
//
var result = false;
//
// Validate Args ...
if (!source.IsValid () ||
!source.Callees.HasChild () ||
connectionId.IsNullOrEmpty ()
) {
return result;
}
//
result = source.Callees.Any (callee => callee.ConnectionId
.ToNormalString () == connectionId
.ToNormalString ());
//
return result;
}
/// <summary>
/// Get Receivers ...
/// </summary>
/// <param name="source"></param>
/// <returns></returns>
public static IReadOnlyList<string> GetReceivers (this XWebRTCConnectionDto source) {
//
var result = new List<string> ();
//
// Validate Args ...
if (!source.IsValid ()) {
return result;
}
//
// Add Caller ...
result.Add (source.CallerConnectionId);
//
// Add Callees ...
source.Callees
.ToList ()
.ForEach (callee => {
result.Add (callee.ConnectionId);
});
//
return result;
}
/// <summary>
/// Retrieve Callee from Callees ...
/// </summary>
/// <param name="source"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
public static XWebRTCCalleeDto GetCallee (
this XWebRTCConnectionDto source,
string connectionId
) {
//
// Validate Args ...
if (!source.IsValid () ||
connectionId.IsNullOrEmpty ()
) {
return null;
}
//
// Check Connection Id is In Callees or not ...
var isInCallees = source.IsInCallees (connectionId);
if (!isInCallees) {
return null;
}
//
// retrieve result ...
var result = source.Callees
.FirstOrDefault (callee => callee.ConnectionId
.ToNormalString () == connectionId
.ToNormalString ()
);
//
// return result ...
return result;
}
}
}
-20
View File
@@ -1,20 +0,0 @@
using System.Threading.Tasks;
using xPushService.Models;
namespace xPushService.Interfaces {
public interface IXAuthorizedPushActions {
/// <summary>
/// an authenticated user can push a message to others ...
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
Task UserMessageAsync (XPushMessage message);
/// <summary>
/// an admin user can push a message to others ...
/// </summary>
/// <param name="message"></param>
/// <returns></returns>
Task AdminMessageAsync (XPushMessage message);
}
}
+1 -23
View File
@@ -1,27 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using xPushService.Models;
namespace xPushService.Interfaces
{
public interface IXBaseHub
{
Task OnConnectedAsync();
Task OnDisconnectedAsync(Exception exception);
Task NotifyNewConnection(string connectionId);
Task UpdateLastSeen();
Task PushMessageAsync(XPushMessage message);
Task AuthorizedMessageAsync(XPushMessage message);
Task PushMessageToAll(XPushMessage message);
Task PushMessageToConnection(
string connectionId,
XPushMessage message
);
Task PushMessageToConnections(
IEnumerable<string> connectionIds,
XPushMessage message
);
}
{ }
}
+5
View File
@@ -0,0 +1,5 @@
namespace xPushService.Interfaces
{
public interface IXBaseWebRTCHub : IXBaseHub
{}
}
-84
View File
@@ -1,84 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using xPushService.Models;
namespace xPushService.Interfaces {
public interface IXGroupsPushActions {
/// <summary>
/// send a message to specific group ...
/// </summary>
/// <param name="groupName"></param>
/// <param name="message"></param>
/// <returns></returns>
Task<bool> SendMessageToGroup (
string groupName,
XPushMessage message
);
/// <summary>
/// send a message to specific groups ...
/// </summary>
/// <param name="groupNames"></param>
/// <param name="message"></param>
/// <returns></returns>
Task<bool> SendMessageToGroups (
IEnumerable<string> groupNames,
XPushMessage message
);
/// <summary>
/// add a connection to specific group ...
/// </summary>
/// <param name="connectionId"></param>
/// <param name="groupName"></param>
/// <returns></returns>
Task<bool> AddConnectionToGroup (
string connectionId,
string groupName
);
/// <summary>
/// remove specific connection from a group ...
/// </summary>
/// <param name="connectionId"></param>
/// <param name="groupName"></param>
/// <returns></returns>
Task<bool> RemoveConnectionFromGroup (
string connectionId,
string groupName
);
/// <summary>
/// retrieve all groups name ...
/// </summary>
/// <returns></returns>
Task<IEnumerable<string>> GetGroupNames ();
/// <summary>
/// retrieve all groups with it's connections ...
/// </summary>
/// <returns></returns>
Task<IEnumerable<XPushGroupDto>> GetGroups ();
/// <summary>
/// remove all connections of specific group ...
/// </summary>
/// <param name="groupName"></param>
/// <returns></returns>
Task<bool> RemoveGroupConnections (string groupName);
/// <summary>
/// retrieve all groups name for specific connection ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
Task<IEnumerable<string>> GetConnectionGroups (string connectionId);
/// <summary>
/// retrieve all connections in specific group ...
/// </summary>
/// <param name="groupName"></param>
/// <returns></returns>
Task<IEnumerable<XPushConnectionDto>> GetGroupConnections (string groupName);
}
}
-108
View File
@@ -1,108 +0,0 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using xModels.Dtos;
using xModels.Interfaces;
using xPushService.Models;
namespace xPushService.Interfaces {
public interface IXPushConnectionStore : IXBaseStore<XPushConnectionDto, string> {
//
#region Custom ...
/// <summary>
/// retrieve specific connection by it's Id ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
Task<XPushConnectionDto> GetByConnectionId (string connectionId);
/// <summary>
/// retrieve specific user's connections ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
Task<IEnumerable<XPushConnectionDto>> GetByUserName (string userName);
/// <summary>
/// retrieve specific user's connected device connection
/// </summary>
/// <param name="userName"></param>
/// <param name="device"></param>
/// <returns></returns>
Task<XPushConnectionDto> GetByUserDevice (string userName, XDeviceDto device);
/// <summary>
/// check a connection exists or not by it's id ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
Task<bool> IsExistsConnectionId (string connectionId);
/// <summary>
/// check specific user connected or not ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
Task<bool> IsExistsUser (string userName);
/// <summary>
/// retrieve specific user's connected devices ...
/// </summary>
/// <param name="userName"></param>
/// <param name="device"></param>
/// <returns></returns>
Task<IEnumerable<XDeviceDto>> GetUserDevices (string userName);
/// <summary>
/// remove specific connection by it's id ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
Task<bool> RemoveByConnectionId (string connectionId);
/// <summary>
/// remove specified user's connected device connection ...
/// </summary>
/// <param name="userName"></param>
/// <param name="device"></param>
/// <returns></returns>
Task<bool> RemoveByUserDevice (string userName, XDeviceDto device);
/// <summary>
/// remove specific user's all connected devices ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
Task<bool> RemoveUser (string userName);
/// <summary>
/// Get specific connections last seen ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
Task<DateTime> GetLastSeenByConnectionId (string connectionId);
/// <summary>
/// get specific user's last seen ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
Task<DateTime> GetLastSeenByUserName (string userName);
/// <summary>
/// get specific user's connected device last seen ...
/// </summary>
/// <param name="userName"></param>
/// <param name="device"></param>
/// <returns></returns>
Task<DateTime> GetLastSeenByUserDevice (string userName, XDeviceDto device);
/// <summary>
/// Update Connection last seen ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
Task<bool> UpdateLastSeen(string connectionId);
#endregion
}
}
@@ -1,8 +0,0 @@
using xModels.Interfaces;
using xPushService.Models;
namespace xPushService.Interfaces
{
public interface IXPushConnectionStoreEvents : IXBaseStoreEvents<XPushConnectionDto, string>
{ }
}
-8
View File
@@ -1,8 +0,0 @@
using xModels.Interfaces;
using xPushService.Models;
namespace xPushService.Interfaces
{
public interface IXPushGroupStore : IXBaseStore<XPushGroupDto, string>
{ }
}
-8
View File
@@ -1,8 +0,0 @@
using xModels.Interfaces;
using xPushService.Models;
namespace xPushService.Interfaces
{
public interface IXPushGroupStoreEvents : IXBaseStoreEvents<XPushGroupDto, string>
{}
}
-12
View File
@@ -1,12 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace xPushService.Interfaces
{
public interface IXPushProvider
{
}
}
-105
View File
@@ -1,105 +0,0 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using xModels.Dtos;
using xPushService.Models;
namespace xPushService.Interfaces {
public interface IXUserPushActions {
/// <summary>
/// add an specific user to a group ...
/// </summary>
/// <param name="userName"></param>
/// <param name="groupName"></param>
/// <returns></returns>
Task<bool> AddUserToGroup (
string userName,
string groupName
);
/// <summary>
/// add an specific user's connected device to a group ...
/// </summary>
/// <param name="userName"></param>
/// <param name="groupName"></param>
/// <param name="device"></param>
/// <returns></returns>
Task<bool> AddUserDeviceToGroup (
string userName,
string groupName,
XDeviceDto device
);
/// <summary>
/// remove a user from specific groups ...
/// </summary>
/// <param name="userName"></param>
/// <param name="groupName"></param>
/// <returns></returns>
Task<bool> RemoveUserFromGroup (
string userName,
string groupName
);
/// <summary>
/// remove specific user's connected device from a group ...
/// </summary>
/// <param name="userName"></param>
/// <param name="groupName"></param>
/// <param name="device"></param>
/// <returns></returns>
Task<bool> RemoveUserDeviceFromGroup (
string userName,
string groupName,
XDeviceDto device
);
/// <summary>
/// send a message to specific user ...
/// </summary>
/// <param name="userName"></param>
/// <param name="message"></param>
/// <returns></returns>
Task<bool> SendMessageToUser (
string userName,
XPushMessage message
);
/// <summary>
/// send a message to a user's specific connected device ...
/// </summary>
/// <param name="userName"></param>
/// <param name="message"></param>
/// <param name="device"></param>
/// <returns></returns>
Task<bool> SendMessageToUserDevice (
string userName,
XPushMessage message,
XDeviceDto device
);
/// <summary>
/// send a message to specific users ...
/// </summary>
/// <param name="userNamea"></param>
/// <param name="message"></param>
/// <returns></returns>
Task<bool> SendMessageToUsers (
IEnumerable<string> userNames,
XPushMessage message
);
/// <summary>
/// retrieve all users groups ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
Task<IEnumerable<string>> GetUserGroups (string userName);
/// <summary>
/// retrieve specific user's connected device ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
Task<IEnumerable<XPushConnectionDto>> GetUserConnections (string userName);
}
}
-6
View File
@@ -1,6 +0,0 @@
using xModels.Interfaces;
using xPushService.Models;
namespace xPushService.Interfaces {
public interface IXWebRTCConnectionStore : IXBaseStore<XWebRTCConnectionDto, string> { }
}
@@ -1,8 +0,0 @@
using xModels.Interfaces;
using xPushService.Models;
namespace xPushService.Interfaces
{
public interface IXWebRTCConnectionStoreEvents : IXBaseStoreEvents<XWebRTCConnectionDto, string>
{ }
}
+34
View File
@@ -0,0 +1,34 @@
using xModels.Base;
using xIdentityModels.Constants;
using System;
using System.Collections.Generic;
namespace xPushService.Models
{
public class XHubUserInfo : XBaseDto
{
//
#region Properties ...
public string UserId { get; set; }
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Picture { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public XGender Gender { get; set; }
public bool IsBanned { get; set; }
public bool IsEnabled { get; set; }
public bool EmailConfirmed { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public long? ExpiredOn { get; set; }
public long? AuthenticatedOn { get; set; }
public DateTime? BrithDate { get; set; }
public IEnumerable<string> Issuers { get; set; } = new HashSet<string>();
public IEnumerable<string> Audiences { get; set; } = new HashSet<string>();
public IEnumerable<string> ClientIds { get; set; } = new HashSet<string>();
public IEnumerable<string> Scopes { get; set; } = new HashSet<string>();
public IEnumerable<string> Roles { get; set; } = new HashSet<string>();
#endregion
}
}
-35
View File
@@ -1,35 +0,0 @@
using System;
using xModels.Base;
using xModels.Dtos;
namespace xPushService.Models {
/// <summary>
/// a Hub Connection ...
/// </summary>
public class XPushConnectionDto : XBaseStorableDto<string> {
/// <summary>
/// Connection Id ...
/// </summary>
/// <value></value>
public override string Id { get; set; }
/// <summary>
/// Connected User Name ...
/// </summary>
/// <value></value>
public string User { get; set; }
/// <summary>
/// Connected Hub Type Name ...
/// </summary>
public string Type { get; set; }
/// <summary>
/// Connected User Device ...
/// </summary>
/// <value></value>
public XDeviceDto Device { get; set; }
/// <summary>
/// Connected User's Last Seen ...
/// </summary>
/// <value></value>
public DateTime LastSeen { get; set; }
}
}
-9
View File
@@ -1,9 +0,0 @@
using System.Collections.Generic;
using xModels.Base;
namespace xPushService.Models {
public class XPushGroupDto : XBaseStorableDto<string> {
public override string Id { get; set; }
public List<string> Connections { get; set; }
}
}
-50
View File
@@ -1,50 +0,0 @@
using System;
namespace xPushService.Models {
public class XPushMessage {
/// <summary>
/// Specify the Type of Push Notification ...
/// </summary>
/// <value></value>
public string Type { get; set; }
/// <summary>
/// Specify the Topic of PushNotification ...
/// NOTE: XPushTopic enum contains default Values and User can Extends it ...
/// </summary>
/// <value></value>
public string Topic { get; set; }
/// <summary>
/// Specify the Action Name by passing String Values ...
/// NOTE: XPushAction enum contains default Values for Actions ...
/// </summary>
/// <value></value>
public string Action { get; set; }
/// <summary>
/// if this is a User Push Action, we had to pass Actor ...
/// </summary>
/// <value></value>
public string Actor { get; set; }
/// <summary>
/// in CRUD actions or some Custom Actions, we can pass propper data
/// to clients ...
/// </summary>
/// <value></value>
public string Payload { get; set; }
/// <summary>
/// the message or additional Informations for passing to client ...
/// </summary>
/// <value></value>
public string Message { get; set; }
/// <summary>
/// Push notification date and time ...
/// </summary>
/// <value></value>
public DateTime TimeStamp { get; set; }
}
}
-34
View File
@@ -1,34 +0,0 @@
using System;
using xModels.Base;
using xModels.Dtos;
using xPushService.Constants;
namespace xPushService.Models {
public class XWebRTCCalleeDto : XBaseDto {
/// <summary>
/// Callee User Name ...
/// </summary>
/// <value></value>
public string User { get; set; }
/// <summary>
/// Callee Device ...
/// </summary>
/// <value></value>
public XDeviceDto Device { get; set; }
/// <summary>
/// Calee Connection Id ...
/// </summary>
/// <value></value>
public string ConnectionId { get; set; }
/// <summary>
/// call end time ...
/// </summary>
/// <value></value>
public DateTime EndTime { get; set; }
/// <summary>
/// call end reason ...
/// </summary>
/// <value></value>
public XCallEndReason EndReason { get; set; }
}
}
-49
View File
@@ -1,49 +0,0 @@
using System;
using System.Collections.Generic;
using xModels.Base;
using xModels.Dtos;
using xPushService.Constants;
namespace xPushService.Models {
/// <summary>
/// describe a WebRTC Call ...
/// </summary>
public class XWebRTCConnectionDto : XBaseStorableDto<string> {
public override string Id { get; set; }
/// <summary>
/// Call Type ...
/// </summary>
/// <value></value>
public XCallType Type { get; set; }
/// <summary>
/// call request Time ...
/// </summary>
/// <value></value>
public DateTime RequestTime { get; set; }
/// <summary>
/// Payload object ...
/// </summary>
/// <value></value>
public object Payload { get; set; }
/// <summary>
/// Caller User Name ...
/// </summary>
/// <value></value>
public string CallerUser { get; set; }
/// <summary>
/// Caller Device ...
/// </summary>
/// <value></value>
public XDeviceDto CallerDevice { get; set; }
/// <summary>
/// Caller Connection Id ...
/// </summary>
/// <value></value>
public string CallerConnectionId { get; set; }
/// <summary>
/// Callees Informations ...
/// </summary>
/// <value></value>
public IEnumerable<XWebRTCCalleeDto> Callees { get; set; }
}
}
-22
View File
@@ -1,22 +0,0 @@
using System.Collections.Generic;
using xModels.Base;
namespace xPushService.Models {
public class XWebRTCSignalDto : XBaseDto {
/// <summary>
/// Signalign Offer ...
/// </summary>
/// <value></value>
public object Offer { get; set; }
/// <summary>
/// Signaling Answer ...
/// </summary>
/// <value></value>
public object Answer { get; set; }
/// <summary>
/// Signaling Candidates
/// </summary>
/// <value></value>
public IEnumerable<object> Cadidates { get; set; }
}
}
@@ -1,41 +0,0 @@
using System;
using Microsoft.AspNetCore.SignalR.Client;
using xPushService.Configurations;
namespace xPushService.Policies {
public class XPushServiceConnectionRetryPolicy : IRetryPolicy {
//
#region Props ...
//
Exception retryReason = null;
long previousRetryCount = 0;
TimeSpan elapsedMilliseconds;
//
private readonly XPushServiceConfiguration config;
#endregion
//
#region Constructor ...
public XPushServiceConnectionRetryPolicy (
XPushServiceConfiguration config
) {
this.config = config;
}
#endregion
public TimeSpan? NextRetryDelay (RetryContext retryContext) {
//
this.retryReason = retryContext.RetryReason;
this.previousRetryCount = retryContext.PreviousRetryCount;
this.elapsedMilliseconds = retryContext.ElapsedTime;
//
if (retryContext.PreviousRetryCount < config.PushConnectionMaxRetry) {
return TimeSpan.FromMilliseconds (this.config.PushConnectionReconnectDelay);
} else {
return null;
}
}
}
}
-5
View File
@@ -1,5 +0,0 @@
using xPushService.Interfaces;
namespace xPushService.Providers {
public class XPushProvider : IXPushProvider { }
}
-321
View File
@@ -1,321 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using xCommons.Extensions;
using xExceptions.Constants;
using xModels.Base;
using xModels.Dtos;
using xModels.Providers;
using xPushService.Interfaces;
using xPushService.Models;
namespace xPushService.Store
{
public class XPushConnectionInMemoryStore : XBaseInMemoryStore<XPushConnectionDto, string>, IXPushConnectionStore
{
//
#region Constructor ...
public XPushConnectionInMemoryStore(
IXPushConnectionStoreEvents events = null
) : base(events) {}
#endregion
//
#region Custom ...
/// <summary>
/// retrieve specific connection by it's Id ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
public Task<XPushConnectionDto> GetByConnectionId(string connectionId)
{
return Get(connectionId);
}
/// <summary>
/// retrieve specific user's connections ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public Task<IEnumerable<XPushConnectionDto>> GetByUserName(string userName)
{
return FindMany(c => c.User.ToNormalString() == userName.ToNormalString());
}
/// <summary>
/// retrieve specific user's connected device connection
/// </summary>
/// <param name="userName"></param>
/// <param name="device"></param>
/// <returns></returns>
public Task<XPushConnectionDto> GetByUserDevice(string userName, XDeviceDto device)
{
return FindOne(c =>
c.User.ToNormalString() == userName.ToNormalString() &&
c.Device.IsSameContent(
device, null, null, null, false
)
);
}
/// <summary>
/// check a connection exists or not by it's id ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
public Task<bool> IsExistsConnectionId(string connectionId)
{
return IsExistsByKey(connectionId);
}
/// <summary>
/// check specific user connected or not ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public Task<bool> IsExistsUser(string userName)
{
return GetByUserName(userName)
.ContinueWith(findTask =>
{
//
var findResult = findTask
.RunTask();
//
var result = findResult.Any();
return result;
});
}
/// <summary>
/// retrieve specific user's connected devices ...
/// </summary>
/// <param name="userName"></param>
/// <param name="device"></param>
/// <returns></returns>
public Task<IEnumerable<XDeviceDto>> GetUserDevices(string userName)
{
return GetByUserName(userName)
.ContinueWith(userConnectionsTask =>
{
//
var userConnections = userConnectionsTask
.RunTask();
//
var result = userConnections.Select(c => c.Device);
return result;
});
}
/// <summary>
/// remove specific connection by it's id ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
public Task<bool> RemoveByConnectionId(string connectionId)
{
return RemoveByKey(connectionId);
}
/// <summary>
/// remove specified user's connected device connection ...
/// </summary>
/// <param name="userName"></param>
/// <param name="device"></param>
/// <returns></returns>
public Task<bool> RemoveByUserDevice(string userName, XDeviceDto device)
{
return GetByUserDevice(
device: device,
userName: userName
)
.ContinueWith(connectionTask =>
{
//
var connection = connectionTask
.RunTask();
//
if (connection.IsNull())
{
return false;
}
//
var result = Remove(connection)
.RunTask();
return result;
});
}
/// <summary>
/// remove specific user's all connected devices ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public Task<bool> RemoveUser(string userName)
{
return GetByUserName(userName)
.ContinueWith(connectionsTask =>
{
//
var connections = connectionsTask
.RunTask();
//
if (!connections.HasChild())
{
return false;
}
//
var result = RemoveMany(new XBaseRangeRequest<XPushConnectionDto>
{
Items = connections
})
.RunTask();
//
return result;
});
}
/// <summary>
/// Get specific connections last seen ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
public Task<DateTime> GetLastSeenByConnectionId(string connectionId)
{
return GetByConnectionId(connectionId)
.ContinueWith(connectionTask =>
{
//
var connection = connectionTask
.RunTask();
//
if (connection.IsNull())
{
throw XException.NotFound.ToException();
}
//
var result = connection.LastSeen;
return result;
});
}
/// <summary>
/// get specific user's last seen ...
/// </summary>
/// <param name="userName"></param>
/// <returns></returns>
public Task<DateTime> GetLastSeenByUserName(string userName)
{
return GetByUserName(userName)
.ContinueWith(connectionsTask =>
{
//
var connections = connectionsTask
.RunTask();
//
if (!connections.HasChild())
{
throw XException.NotFound.ToException();
}
//
var result = connections
.Select(c => c.LastSeen)
.Max();
//
return result;
});
}
/// <summary>
/// get specific user's connected device last seen ...
/// </summary>
/// <param name="userName"></param>
/// <param name="device"></param>
/// <returns></returns>
public Task<DateTime> GetLastSeenByUserDevice(string userName, XDeviceDto device)
{
return GetByUserDevice(
device: device,
userName: userName
)
.ContinueWith(connectionTask =>
{
//
var connection = connectionTask
.RunTask();
//
if (connection.IsNull())
{
throw XException.NotFound.ToException();
}
//
var result = connection.LastSeen;
return result;
});
}
/// <summary>
/// Update Connection last seen ...
/// </summary>
/// <param name="connectionId"></param>
/// <returns></returns>
public Task<bool> UpdateLastSeen(string connectionId)
{
return IsExistsConnectionId(connectionId)
.ContinueWith(isExistsTask =>
{
//
// define empty result ...
var result = false;
//
// run task and get result ...
result = isExistsTask
.RunTask();
//
// check result is false ...
if (!result)
{
return result;
}
//
// retreive connection ...
var connection = GetByConnectionId(connectionId)
.RunTask();
result = !connection.IsNull();
if (!result)
{
return result;
}
//
// Update Connection last seen ...
connection.LastSeen = DateTime.UtcNow;
var updatedConnection = Update(connection)
.RunTask();
result = !updatedConnection.IsNull();
//
return result;
});
}
#endregion
}
}
-16
View File
@@ -1,16 +0,0 @@
using xModels.Providers;
using xPushService.Interfaces;
using xPushService.Models;
namespace xPushService.Store
{
public class XPushGroupInMemoryStore : XBaseInMemoryStore<XPushGroupDto, string>, IXPushGroupStore
{
//
#region Constructor ...
public XPushGroupInMemoryStore(
IXPushGroupStoreEvents events = null
) : base(events) { }
#endregion
}
}
-16
View File
@@ -1,16 +0,0 @@
using xModels.Providers;
using xPushService.Interfaces;
using xPushService.Models;
namespace xPushService.Store
{
public class XWebRTCConnectionInMemoryStore : XBaseInMemoryStore<XWebRTCConnectionDto, string>, IXWebRTCConnectionStore
{
//
#region Constructor ...
public XWebRTCConnectionInMemoryStore(
IXWebRTCConnectionStoreEvents events = null
) : base(events) { }
#endregion
}
}
+1
View File
@@ -28,6 +28,7 @@
<ProjectReference Include="..\xModels\xModels.csproj" />
<ProjectReference Include="..\xCommons\xCommons.csproj" />
<ProjectReference Include="..\xIdentityService\xIdentityService.csproj" />
</ItemGroup>
<!-- Package Dependencies -->