From c1cc975fcb78e4e7ace4d0d3978b584b68c666c9 Mon Sep 17 00:00:00 2001 From: Hadi Khazaee Asl Date: Fri, 28 Nov 2025 07:53:17 +0330 Subject: [PATCH] add support for XWebinarGroupEntity and it's InMemory Repository and also Register it's required Services and usage in WebinarHub ... --- DI/XDIHelperExtension.cs | 15 ++- Hubs/XWebinarHub.cs | 131 ++++++++++++++++++++++++- Interfaces/IXWebinarGroupStore.cs | 11 +++ Models/Entities/XWebinarGroupEntity.cs | 13 +++ Providers/XWebinarGroupStore.cs | 20 ++++ xWebinarService.csproj | 4 +- 6 files changed, 184 insertions(+), 10 deletions(-) create mode 100644 Interfaces/IXWebinarGroupStore.cs create mode 100644 Models/Entities/XWebinarGroupEntity.cs create mode 100644 Providers/XWebinarGroupStore.cs diff --git a/DI/XDIHelperExtension.cs b/DI/XDIHelperExtension.cs index c19f9ad..627befe 100644 --- a/DI/XDIHelperExtension.cs +++ b/DI/XDIHelperExtension.cs @@ -1,12 +1,16 @@ using System; using Microsoft.Extensions.DependencyInjection; using xCommons.Extensions; +using xDataService.Interfaces; +using xDataService.Providers; using xExceptions.Constants; using xWebinarService.Interfaces; using xWebinarService.Interfaces.Entities; +using xWebinarService.Models.Entities; using xWebinarService.Providers; -namespace xWebinarService.DI { +namespace xWebinarService.DI +{ public static class XDIHelperExtension { /// @@ -89,6 +93,11 @@ namespace xWebinarService.DI { throw exception; } + // + // Register Webinar Group In Memory Repository ... + services.AddSingleton, XGuidKeyGenerator>(); + services.Add(new ServiceDescriptor(typeof(IXWebinarGroupStore), typeof(XWebinarGroupStore), ServiceLifetime.Singleton)); + // // Register Resource Providers ... services.Add(new ServiceDescriptor(typeof(IXWebinarTitleResourceProvider), typeof(XWebinarTitleResourceProvider), lifeTime)); @@ -97,11 +106,11 @@ namespace xWebinarService.DI { // // Register Main Provider ... services.Add(new ServiceDescriptor(typeof(IXWebinarProvider), typeof(XWebinarProvider), lifeTime)); - + // Log("AddWebinarService Succeed ..."); } #endregion - + } } \ No newline at end of file diff --git a/Hubs/XWebinarHub.cs b/Hubs/XWebinarHub.cs index 9dca8ec..b281e16 100644 --- a/Hubs/XWebinarHub.cs +++ b/Hubs/XWebinarHub.cs @@ -1,18 +1,18 @@ using System; -using System.Text; +using System.Collections; +using System.Collections.Generic; +using System.Linq; using System.Threading.Tasks; -using System.Xml.Linq; using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.SignalR; using Microsoft.Extensions.Logging; using xCommons.Extensions; using xExceptions.Constants; -using xIdentityModels.Models; using xPushService.Base; using xPushService.Extensions; using xWebinarService.Constants; -using xWebinarService.Models.Dtos; using xWebinarService.Interfaces; +using xWebinarService.Models.Entities; namespace xWebinarService.Hubs { @@ -21,16 +21,19 @@ namespace xWebinarService.Hubs // #region Props ... public readonly IXWebinarProvider webinarProvider; + private readonly IXWebinarGroupStore webinarGroupStore; #endregion // #region Constructor ... public XWebinarHub( ILogger logger, - IXWebinarProvider webinarProvider + IXWebinarProvider webinarProvider, + IXWebinarGroupStore webinarGroupStore ) : base(logger) { this.webinarProvider = webinarProvider; + this.webinarGroupStore = webinarGroupStore; } #endregion @@ -107,6 +110,35 @@ namespace xWebinarService.Hubs // // Create a Group and Put User on it ... await Groups.AddToGroupAsync(connectionId, webinarId.ToString()); + + // + // Check Exists or not ... + var connection = new XHubConnectionDto + { + UserId = userInfo.UserId, + ConnectionId = connectionId, + Username = userInfo.UserName, + }; + var groupEntity = await webinarGroupStore.FindOneAsync(x => x.WebinarId == webinarId); + if (!groupEntity.IsNullOrDefault()) + { + // + // Update ... + groupEntity.Connections.Clear(); + groupEntity.Connections.Add(connection); + await webinarGroupStore.UpdateAsync(groupEntity.Id, groupEntity); + } + else + { + // + // Add ... + groupEntity = new XWebinarGroupEntity + { + WebinarId = webinarId + }; + groupEntity.Connections.Add(connection); + await webinarGroupStore.AddAsync(groupEntity); + } } catch { } } @@ -183,6 +215,14 @@ namespace xWebinarService.Hubs var webinarName = webinarId.ToString(); await Clients.OthersInGroup(webinarName).SendAsync(XWebinarHubAction.WebinarClosed.ToString()); await Groups.RemoveFromGroupAsync(connectionId, webinarName); + + // + // Check Exists or not ... + var groupEntity = await webinarGroupStore.FindOneAsync(x => x.WebinarId == webinarId); + if (!groupEntity.IsNullOrDefault()) + { + await webinarGroupStore.RemoveAsync(groupEntity.Id); + } } catch { } } @@ -266,6 +306,33 @@ namespace xWebinarService.Hubs userInfo.UserId, userInfo.UserName ); + + // + // Check Exists or not ... + var connection = new XHubConnectionDto + { + UserId = userInfo.UserId, + ConnectionId = connectionId, + Username = userInfo.UserName, + }; + var groupEntity = await webinarGroupStore.FindOneAsync(x => x.WebinarId == webinarId); + if (!groupEntity.IsNullOrDefault()) + { + // + // Check Current User ID Exists ... + var userConnection = groupEntity.Connections.FirstOrDefault(c => c.UserId == userInfo.UserId); + if (!userConnection.IsNullOrDefault()) + { + userConnection.ConnectionId = connectionId; + } + else + { + groupEntity.Connections.Add(connection); + } + + // + await webinarGroupStore.UpdateAsync(groupEntity.Id, groupEntity); + } } catch { } @@ -350,11 +417,65 @@ namespace xWebinarService.Hubs userInfo.UserId, userInfo.UserName ); + + // + // Check Exists or not ... + var groupEntity = await webinarGroupStore.FindOneAsync(x => x.WebinarId == webinarId); + if (!groupEntity.IsNullOrDefault()) + { + // + // Check Current User ID Exists ... + var userConnection = groupEntity.Connections.FirstOrDefault(c => c.ConnectionId == connectionId); + if (!userConnection.IsNullOrDefault()) + { + groupEntity.Connections.Remove(userConnection); + } + + // + await webinarGroupStore.UpdateAsync(groupEntity.Id, groupEntity); + } } catch { } } + /// + /// Return a Collection of Webinars Visitors ... + /// + /// + /// + [Authorize] + public async Task> WebinarVisitors(Guid webinarId) + { + // + var result = new List(); + + // + // Reading and Validate Requirements ... + var userInfo = Context.GetUserInfo(); + var connectionId = Context.ConnectionId; + + + // + // Check Group Exists ... + var groupEntity = await webinarGroupStore.FindOneAsync(x => x.WebinarId == webinarId); + if (!groupEntity.IsNullOrDefault()) + { + // + // Validate Requester is a Viewer ... + var connection = groupEntity.Connections.FirstOrDefault(c => c.ConnectionId == connectionId || + c.UserId == userInfo.UserId + ); + if (!connection.IsNullOrDefault()) + { + result = groupEntity.Connections; + } + } + + // + return result; + } + /// /// Send a Message to Specified Webinar ... /// diff --git a/Interfaces/IXWebinarGroupStore.cs b/Interfaces/IXWebinarGroupStore.cs new file mode 100644 index 0000000..b238400 --- /dev/null +++ b/Interfaces/IXWebinarGroupStore.cs @@ -0,0 +1,11 @@ +using System; +using xDataService.Interfaces; +using xWebinarService.Models.Entities; + +namespace xWebinarService.Interfaces +{ + public interface IXWebinarGroupStore : IXBaseRepository + { + + } +} \ No newline at end of file diff --git a/Models/Entities/XWebinarGroupEntity.cs b/Models/Entities/XWebinarGroupEntity.cs new file mode 100644 index 0000000..f6f3cc5 --- /dev/null +++ b/Models/Entities/XWebinarGroupEntity.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using xModels.Base; +using xPushService.Base; + +namespace xWebinarService.Models.Entities +{ + public class XWebinarGroupEntity : XBaseGuidIDEntity + { + public Guid WebinarId { get; set; } + public List Connections { get; set; } = new List(); + } +} \ No newline at end of file diff --git a/Providers/XWebinarGroupStore.cs b/Providers/XWebinarGroupStore.cs new file mode 100644 index 0000000..35c24d6 --- /dev/null +++ b/Providers/XWebinarGroupStore.cs @@ -0,0 +1,20 @@ +using System; +using xDataService.Configuration; +using xDataService.InMemRepositories; +using xDataService.Interfaces; +using xWebinarService.Interfaces; +using xWebinarService.Models.Entities; + +namespace xWebinarService.Providers +{ + public class XWebinarGroupStore : XBaseInMemoryRepositoy, IXWebinarGroupStore + { + public XWebinarGroupStore( + XDataServiceConfiguration configuration, + IXKeyGenerator keyGenerator = null, + IXBaseRepositoryEvents baseRepositoryEvents = null + ) : base(configuration, keyGenerator, baseRepositoryEvents) + { + } + } +} \ No newline at end of file diff --git a/xWebinarService.csproj b/xWebinarService.csproj index 563e46e..7ac77bb 100644 --- a/xWebinarService.csproj +++ b/xWebinarService.csproj @@ -22,7 +22,7 @@ - + @@ -31,8 +31,8 @@ -