Initial Commit ...
This commit is contained in:
@@ -0,0 +1,8 @@
|
|||||||
|
#
|
||||||
|
# DotNet ...
|
||||||
|
bin
|
||||||
|
obj
|
||||||
|
|
||||||
|
#
|
||||||
|
# Natural Docs ...
|
||||||
|
Documentation/*
|
||||||
@@ -0,0 +1,363 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
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>
|
||||||
|
public abstract class XBaseHub : Hub {
|
||||||
|
//
|
||||||
|
#region Props ...
|
||||||
|
protected readonly IXPushGroupStore groupStore;
|
||||||
|
protected readonly IXPushConnectionStore connectionStore;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Constructor ...
|
||||||
|
public XBaseHub (
|
||||||
|
IXPushGroupStore groupStore,
|
||||||
|
IXPushConnectionStore connectionStore
|
||||||
|
) : base () {
|
||||||
|
//
|
||||||
|
this.groupStore = groupStore;
|
||||||
|
this.connectionStore = connectionStore;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Abstract ...
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
#region EnevtHandlers ...
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Overrides ...
|
||||||
|
public override Task OnConnectedAsync () {
|
||||||
|
//
|
||||||
|
var connection = GetConnection ();
|
||||||
|
if (!connection.IsNull ()) {
|
||||||
|
//
|
||||||
|
connectionStore
|
||||||
|
.Add (connection)
|
||||||
|
.RunTask ();
|
||||||
|
|
||||||
|
//
|
||||||
|
var count = connectionStore
|
||||||
|
.Count ()
|
||||||
|
.RunTask ();
|
||||||
|
|
||||||
|
//
|
||||||
|
Console.WriteLine ($"Count After Coonected: {count}");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
return base.OnConnectedAsync ();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override Task OnDisconnectedAsync (Exception exception) {
|
||||||
|
//
|
||||||
|
var connection = GetConnection ();
|
||||||
|
if (!connection.IsNull ()) {
|
||||||
|
//
|
||||||
|
connectionStore
|
||||||
|
.RemoveByConnectionId (connection.Id)
|
||||||
|
.RunTask ();
|
||||||
|
|
||||||
|
//
|
||||||
|
var count = connectionStore
|
||||||
|
.Count ()
|
||||||
|
.RunTask ();
|
||||||
|
|
||||||
|
//
|
||||||
|
Console.WriteLine ($"Count After DisCoonected: {count}");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
return 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,
|
||||||
|
Type = XPushType.System,
|
||||||
|
TimeStamp = DateTime.UtcNow,
|
||||||
|
Topic = (int) XPushType.System,
|
||||||
|
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 GetConnection () {
|
||||||
|
//
|
||||||
|
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 ...
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,87 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,836 @@
|
|||||||
|
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 xPushService.Interfaces;
|
||||||
|
using xPushService.Models;
|
||||||
|
|
||||||
|
namespace xPushService.Base {
|
||||||
|
public abstract class XBaseWebRTCHub : XBaseHub {
|
||||||
|
//
|
||||||
|
#region Props ...
|
||||||
|
protected readonly IXWebRTCConnectionStore webRTCConnectionStore;
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Constructor ...
|
||||||
|
public XBaseWebRTCHub (
|
||||||
|
IXPushGroupStore groupStore,
|
||||||
|
IXPushConnectionStore connectionStore,
|
||||||
|
IXWebRTCConnectionStore webRTCConnectionStore
|
||||||
|
) : base (groupStore, connectionStore) {
|
||||||
|
this.webRTCConnectionStore = webRTCConnectionStore;
|
||||||
|
}
|
||||||
|
#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 ...
|
||||||
|
/// <summary>
|
||||||
|
/// Send PreOffer Call Request ...
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <param name="connectionId"></param>
|
||||||
|
/// <param name="device"></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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Send PreOffer Call Request ...
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="type"></param>
|
||||||
|
/// <param name="user"></param>
|
||||||
|
/// <param name="device"></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);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Cancel or End Requested Call ...
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public Task<bool> CancelCall (
|
||||||
|
string cancellerConnectionId,
|
||||||
|
XCallEndReason reason,
|
||||||
|
XWebRTCConnectionDto request) {
|
||||||
|
//
|
||||||
|
// Validate Args ...
|
||||||
|
var isValid = IsWebRTCConnectionsExists (request)
|
||||||
|
.RunTask ();
|
||||||
|
if (!isValid) {
|
||||||
|
return Task.FromResult (false);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
namespace xPushService.Configurations {
|
||||||
|
public partial class XPushServiceConfiguration {
|
||||||
|
/// <summary>
|
||||||
|
/// Base route of WebSocket Server ...
|
||||||
|
/// </summary>
|
||||||
|
/// <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 ...
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public int PushConnectionMaxRetry { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// add support for message protocol ...
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public bool AddSupportMessageProtocol { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// the delay between two connection try ..
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public int PushConnectionReconnectDelay { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
namespace xPushService.Constants {
|
||||||
|
public enum XCallEndReason {
|
||||||
|
End,
|
||||||
|
Missed,
|
||||||
|
Reject,
|
||||||
|
Canceled,
|
||||||
|
Disconnected
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
namespace xPushService.Constants {
|
||||||
|
public enum XCallType {
|
||||||
|
None,
|
||||||
|
Chat,
|
||||||
|
AudioCall,
|
||||||
|
VideoCall,
|
||||||
|
DesktopShare,
|
||||||
|
AudioConference,
|
||||||
|
VideoConference,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
namespace xPushService.Constants {
|
||||||
|
public partial class XPushServiceConstants {
|
||||||
|
public partial struct XConfigurationNodes {
|
||||||
|
public const string XPushServiceConfiguration = "PushServiceConfiguration";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
using xExceptions.Attributes;
|
||||||
|
|
||||||
|
namespace xPushService.Constants {
|
||||||
|
/// <summary>
|
||||||
|
/// Determines Push Notification Types
|
||||||
|
/// </summary>
|
||||||
|
public enum XPushType {
|
||||||
|
/// System Type Notifications Relate Only to System
|
||||||
|
System,
|
||||||
|
|
||||||
|
/// User Specific Types Of Push Notifications
|
||||||
|
User
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Base Push Actions ...
|
||||||
|
/// </summary>
|
||||||
|
public enum XBasePushAction {
|
||||||
|
[StringValue ("PushMessageAsync")]
|
||||||
|
PushMessage,
|
||||||
|
[StringValue ("UserMessageAsync")]
|
||||||
|
UserMessage,
|
||||||
|
[StringValue ("AdminMessageAsync")]
|
||||||
|
AdminMessage,
|
||||||
|
[StringValue("AuthorizedMessageAsync")]
|
||||||
|
AuthorizedMessage,
|
||||||
|
[StringValue("NotifyNewConnection")]
|
||||||
|
NotifyNewConnection
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
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,
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,289 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using Microsoft.AspNetCore.Builder;
|
||||||
|
using Microsoft.AspNetCore.Http;
|
||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
using Microsoft.Extensions.Configuration;
|
||||||
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Serialization;
|
||||||
|
using xCommons.Extensions;
|
||||||
|
using xExceptions.Constants;
|
||||||
|
using xPushService.Configurations;
|
||||||
|
using xPushService.Constants;
|
||||||
|
using xPushService.Helpers;
|
||||||
|
using xPushService.Interfaces;
|
||||||
|
using xPushService.Providers;
|
||||||
|
using xPushService.Store;
|
||||||
|
|
||||||
|
namespace xPushService.DI {
|
||||||
|
public static partial class XDIHelperExtension {
|
||||||
|
/// <summary>
|
||||||
|
/// Extract Module Configuration from provided IConfiguration
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
/// <returns>an instance of XPushServiceConfiguration</returns>
|
||||||
|
public static XPushServiceConfiguration GetXPushServiceConfiguration (this IConfiguration config) {
|
||||||
|
//
|
||||||
|
var xPushConfigSection = config.GetSection (XPushServiceConstants.XConfigurationNodes.XPushServiceConfiguration);
|
||||||
|
return xPushConfigSection.Get<XPushServiceConfiguration> ();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register XPushServiceHelper ...
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <param name="helper"></param>
|
||||||
|
public static void AddXPushServiceHelper (
|
||||||
|
this IServiceCollection services,
|
||||||
|
XPushServiceHelper helper
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
// Validate Args ...
|
||||||
|
if (helper.IsNull ()) {
|
||||||
|
//
|
||||||
|
Log ("AddXPushServiceHelper failed, helper not provided ...");
|
||||||
|
throw XException.InvalidArgs.ToException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Register Helper ...
|
||||||
|
services.AddSingleton (helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register Module Provided Service on DI
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
public static void AddXPushService (
|
||||||
|
this IServiceCollection services,
|
||||||
|
IConfiguration config,
|
||||||
|
ServiceLifetime lifeTime = ServiceLifetime.Singleton
|
||||||
|
) {
|
||||||
|
AddPushService (
|
||||||
|
services,
|
||||||
|
config.GetXPushServiceConfiguration (),
|
||||||
|
lifeTime
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register Module Provided Service on DI
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
public static void AddXPushService (
|
||||||
|
this IServiceCollection services,
|
||||||
|
XPushServiceConfiguration config,
|
||||||
|
ServiceLifetime lifeTime = ServiceLifetime.Singleton
|
||||||
|
) {
|
||||||
|
AddPushService (
|
||||||
|
services,
|
||||||
|
config,
|
||||||
|
lifeTime
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Use Module Middlewares on Application Builder
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="app"></param>
|
||||||
|
/// <param name="helper"></param>
|
||||||
|
public static void UseXPushService (
|
||||||
|
this IApplicationBuilder app,
|
||||||
|
XPushServiceHelper helper
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
// Validate Args ...
|
||||||
|
var isHelperExists = !helper.IsNull ();
|
||||||
|
if (!isHelperExists) {
|
||||||
|
//
|
||||||
|
Log ("AddXPushServiceHelper failed, helper not provided ...");
|
||||||
|
throw XException.InvalidArgs.ToException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Create an Scope for Accessing Registered Services ...
|
||||||
|
using (var scope = app.ApplicationServices.CreateScope ()) {
|
||||||
|
//
|
||||||
|
// try to Retrieve Configuration ....
|
||||||
|
var config = scope.ServiceProvider.GetService<XPushServiceConfiguration> ();
|
||||||
|
if (
|
||||||
|
config.IsNull () ||
|
||||||
|
config.BaseRoute.IsNullOrEmpty () ||
|
||||||
|
config.BaseRoute.Trim ().IsNullOrEmpty ()
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
Log ("AddXPushServiceHelper failed, Configuration not provided ...");
|
||||||
|
throw XException.InvalidConfiguration.ToException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Normalize Routes ...
|
||||||
|
//
|
||||||
|
// Base Reoute ...
|
||||||
|
config.BaseRoute = config.BaseRoute.ToNormalString ();
|
||||||
|
if (!config.BaseRoute.StartsWith ("/")) {
|
||||||
|
config.BaseRoute = "/" + config.BaseRoute;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
// add XPushService Hub to Helper ...
|
||||||
|
//
|
||||||
|
var hubRoutes = new List<string> ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Try to Register Hubs ...
|
||||||
|
//
|
||||||
|
// Use SignalR in App ...
|
||||||
|
app.UseSignalR (routes => {
|
||||||
|
//
|
||||||
|
helper.GetHubs ().ForEach (hubDescriptor => {
|
||||||
|
//
|
||||||
|
var hubRoute = Path.Combine (config.BaseRoute, hubDescriptor.Route);
|
||||||
|
hubRoutes.Add (hubRoute);
|
||||||
|
Console.WriteLine ($"XPushService HubRoute: {hubRoute}");
|
||||||
|
|
||||||
|
//
|
||||||
|
Type routesType = routes.GetType ();
|
||||||
|
MethodInfo mapHubMethod = routesType
|
||||||
|
.GetMethods ()
|
||||||
|
.SingleOrDefault (m =>
|
||||||
|
m.Name == "MapHub" &&
|
||||||
|
m.GetParameters ().Length == 1
|
||||||
|
);
|
||||||
|
if (mapHubMethod.IsNull ()) {
|
||||||
|
throw XException.ActionFailed.ToException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
object[] genericMapHubMethodArgs = { new PathString (hubRoute) };
|
||||||
|
MethodInfo genericMapHubMethod = mapHubMethod.MakeGenericMethod (hubDescriptor.Hub);
|
||||||
|
genericMapHubMethod.Invoke (routes, genericMapHubMethodArgs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
#region Private ...
|
||||||
|
/// <summary>
|
||||||
|
/// a LogTag for XPushService ...
|
||||||
|
/// </summary>
|
||||||
|
private static string XLogTag = "XPushService";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// print a log in Console ...
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="message"></param>
|
||||||
|
private static void Log (string message) {
|
||||||
|
Console.WriteLine ($"{XLogTag} => {message}");
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Register Push Service ...
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="services"></param>
|
||||||
|
/// <param name="config"></param>
|
||||||
|
/// <param name="lifeTime"></param>
|
||||||
|
private static void AddPushService (
|
||||||
|
IServiceCollection services,
|
||||||
|
XPushServiceConfiguration config,
|
||||||
|
ServiceLifetime lifeTime
|
||||||
|
) {
|
||||||
|
//
|
||||||
|
#region Validate Args ...
|
||||||
|
//
|
||||||
|
var exception = XException.InvalidArgs.ToException ();;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Services ...
|
||||||
|
var isServicesExists = !services.IsNull ();
|
||||||
|
if (!isServicesExists) {
|
||||||
|
//
|
||||||
|
Log ("AddXPushServiceHelper failed, services not provided ...");
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Config ...
|
||||||
|
var isConfigExists = !config.IsNull ();
|
||||||
|
if (!isConfigExists) {
|
||||||
|
//
|
||||||
|
Log ("AddXPushServiceHelper failed, configuration not provided ...");
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Lifetime ...
|
||||||
|
var isLifetimeExists = !lifeTime.IsNull ();
|
||||||
|
if (!isLifetimeExists) {
|
||||||
|
//
|
||||||
|
Log ("AddXPushServiceHelper failed, lifetime not provided ...");
|
||||||
|
throw exception;
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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 ...");
|
||||||
|
groupStore = new XPushGroupInMemoryStore ();
|
||||||
|
services.AddSingleton<IXPushGroupStore> (groupStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
var connectionStore = services.GetRegisteredService<IXPushConnectionStore> ();
|
||||||
|
if (connectionStore.IsNull ()) {
|
||||||
|
//
|
||||||
|
Log ($"there is no provided XPushConnectionStore, try to register XPushConnectionInMemoryStore ...");
|
||||||
|
connectionStore = new XPushConnectionInMemoryStore ();
|
||||||
|
services.AddSingleton<IXPushConnectionStore> (connectionStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
var webRtcConnectionStore = services.GetRegisteredService<IXWebRTCConnectionStore> ();
|
||||||
|
if (webRtcConnectionStore.IsNull ()) {
|
||||||
|
//
|
||||||
|
Log ($"there is no provided XWebRTCConnectionStore, try to register XWebRTCConnectionInMemoryStore ...");
|
||||||
|
webRtcConnectionStore = new XWebRTCConnectionInMemoryStore ();
|
||||||
|
services.AddSingleton<IXWebRTCConnectionStore> (webRtcConnectionStore);
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
// Register SignalR ...
|
||||||
|
var builder = services.AddSignalR ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add NewtonSoftJson Protocol ...
|
||||||
|
builder.AddNewtonsoftJsonProtocol (x => {
|
||||||
|
x.PayloadSerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
|
||||||
|
x.PayloadSerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver ();
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// Register XPushServiceUserNameProvider ...
|
||||||
|
services.AddSingleton<IUserIdProvider, XPushServiceUserNameProvider> ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// add Message Protocol Support ...
|
||||||
|
if (config.AddSupportMessageProtocol) {
|
||||||
|
builder.AddMessagePackProtocol ();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using xCommons.Extensions;
|
||||||
|
using xExceptions.Constants;
|
||||||
|
using xPushService.Base;
|
||||||
|
using xPushService.Models;
|
||||||
|
|
||||||
|
namespace xPushService.Helpers {
|
||||||
|
public class XPushServiceHelper {
|
||||||
|
/// <summary>
|
||||||
|
/// a collection of Hubs for Registring ...
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="XHubDescriptor"></typeparam>
|
||||||
|
/// <returns></returns>
|
||||||
|
private List<XHubDescriptor> hubs = new List<XHubDescriptor> ();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// add specified hub to provided hubs for registration ...
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="reoute"></param>
|
||||||
|
/// <typeparam name="TXHub"></typeparam>
|
||||||
|
public void AddHub<TXHub> (string route) where TXHub : XBaseHub {
|
||||||
|
//
|
||||||
|
#region Validate Args ...
|
||||||
|
//
|
||||||
|
// check route not null ...
|
||||||
|
if (
|
||||||
|
route.IsNullOrEmpty () ||
|
||||||
|
route.Trim ().IsNullOrEmpty ()
|
||||||
|
) {
|
||||||
|
throw XException.InvalidArgs.ToException ();
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Normalize Route ...
|
||||||
|
route = route.ToNormalString ();
|
||||||
|
|
||||||
|
//
|
||||||
|
// check route and hub must be unique ...
|
||||||
|
var isRouteExists = hubs.Any (hd => hd.Route == route);
|
||||||
|
var isHubExists = hubs.Any (hd => hd.Hub == typeof (TXHub));
|
||||||
|
if (
|
||||||
|
isHubExists ||
|
||||||
|
isRouteExists
|
||||||
|
) {
|
||||||
|
throw XException.Duplicate.ToException ();
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
//
|
||||||
|
// Add Provided Hub to List ...
|
||||||
|
hubs.Add (new XHubDescriptor {
|
||||||
|
Route = route,
|
||||||
|
Hub = typeof (TXHub)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// remove an specific hub from provided list ...
|
||||||
|
/// </summary>
|
||||||
|
/// <typeparam name="TXHub"></typeparam>
|
||||||
|
public void RemoveHub<TXHub> () where TXHub : XBaseHub {
|
||||||
|
//
|
||||||
|
var existsHubDescriptor = hubs.SingleOrDefault (hd => hd.Hub == typeof (TXHub));
|
||||||
|
if (!existsHubDescriptor.IsNull ()) {
|
||||||
|
hubs.Remove (existsHubDescriptor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// retrieve provided hubs count ...
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public int Count () {
|
||||||
|
return hubs.Count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// retrieve all provided hubs for registration ...
|
||||||
|
/// </summary>
|
||||||
|
/// <returns></returns>
|
||||||
|
public List<XHubDescriptor> GetHubs () {
|
||||||
|
return hubs;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using xModels.Interfaces;
|
||||||
|
using xPushService.Models;
|
||||||
|
|
||||||
|
namespace xPushService.Interfaces {
|
||||||
|
public interface IXPushGroupStore : IXBaseStore<XPushGroupDto, string> { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace xPushService.Interfaces
|
||||||
|
{
|
||||||
|
public interface IXPushProvider
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
using xModels.Interfaces;
|
||||||
|
using xPushService.Models;
|
||||||
|
|
||||||
|
namespace xPushService.Interfaces {
|
||||||
|
public interface IXWebRTCConnectionStore : IXBaseStore<XWebRTCConnectionDto, string> { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace xPushService.Models {
|
||||||
|
/// <summary>
|
||||||
|
/// Describe a Hub to Register ...
|
||||||
|
/// </summary>
|
||||||
|
public class XHubDescriptor {
|
||||||
|
/// <summary>
|
||||||
|
/// Specified the Hub Route ...
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public string Route { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specified the Hub Class Type ...
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public Type Hub { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,31 @@
|
|||||||
|
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 User Device ...
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public XDeviceDto Device { get; set; }
|
||||||
|
/// <summary>
|
||||||
|
/// Connected User's Last Seen ...
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public DateTime LastSeen { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
using System;
|
||||||
|
using xPushService.Constants;
|
||||||
|
|
||||||
|
namespace xPushService.Models {
|
||||||
|
public class XPushMessage {
|
||||||
|
/// <summary>
|
||||||
|
/// Specify the Type of Push Notification ...
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public XPushType Type { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specify the Topic of PushNotification ...
|
||||||
|
/// NOTE: XPushTopic enum contains default Values and User can Extends it ...
|
||||||
|
/// </summary>
|
||||||
|
/// <value></value>
|
||||||
|
public int 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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
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; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
using xPushService.Interfaces;
|
||||||
|
|
||||||
|
namespace xPushService.Providers {
|
||||||
|
public class XPushProvider : IXPushProvider { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using Microsoft.AspNetCore.SignalR;
|
||||||
|
|
||||||
|
namespace xPushService.Providers {
|
||||||
|
public class XPushServiceUserNameProvider : IUserIdProvider {
|
||||||
|
public string GetUserId (HubConnectionContext connection) {
|
||||||
|
//
|
||||||
|
var result = connection.User?.Identity?.Name;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,283 @@
|
|||||||
|
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 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
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using xModels.Providers;
|
||||||
|
using xPushService.Interfaces;
|
||||||
|
using xPushService.Models;
|
||||||
|
|
||||||
|
namespace xPushService.Store {
|
||||||
|
public class XPushGroupInMemoryStore : XBaseInMemoryStore<XPushGroupDto, string>, IXPushGroupStore { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
using xModels.Providers;
|
||||||
|
using xPushService.Interfaces;
|
||||||
|
using xPushService.Models;
|
||||||
|
|
||||||
|
namespace xPushService.Store {
|
||||||
|
public class XWebRTCConnectionInMemoryStore : XBaseInMemoryStore<XWebRTCConnectionDto, string>, IXWebRTCConnectionStore { }
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<add key="nuget" value="https://api.nuget.org/v3/index.json" protocolVersion="3" />
|
||||||
|
<add key="baget" value="https://nuget.saherelmhub.ir/v3/index.json" protocolVersion="3" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
<!-- Runtime Definition -->
|
||||||
|
<PropertyGroup>
|
||||||
|
<TargetFramework>netstandard2.0</TargetFramework>
|
||||||
|
<PackageId>xDashboard.xPushService</PackageId>
|
||||||
|
<Version>1.0.0</Version>
|
||||||
|
<Authors>Hadi Khazaee Asl</Authors>
|
||||||
|
<Company>SaherElm IT Center</Company>
|
||||||
|
<Description>
|
||||||
|
it is a Part of xDashboard Projects on SaherElm IT Center which provides all required models
|
||||||
|
and actions in related to
|
||||||
|
handling SignalR Push Platforms.
|
||||||
|
</Description>
|
||||||
|
|
||||||
|
<!-- Icon Definition -->
|
||||||
|
<PackageIcon>icon.png</PackageIcon>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<!-- Icon Handling -->
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="../../Resources/Images/favicon.png" Link="icon.png" Pack="true" PackagePath="\icon.png" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Local Dependencies -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="xDashboard.xModels" Version="1.0.0" />
|
||||||
|
<PackageReference Include="xDashboard.xCommons" Version="1.0.0" />
|
||||||
|
|
||||||
|
<!-- <ProjectReference Include="..\xModels\xModels.csproj" /> -->
|
||||||
|
<!-- <ProjectReference Include="..\xCommons\xCommons.csproj" /> -->
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<!-- Package Dependencies -->
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.1.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.Authentication" Version="2.2.0" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Client" Version="3.1.31" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.MessagePack" Version="3.1.31" />
|
||||||
|
<PackageReference Include="Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson" Version="5.0.17" />
|
||||||
|
</ItemGroup>
|
||||||
|
</Project>
|
||||||
Reference in New Issue
Block a user