tgstation-server 6.12.0
The /tg/station 13 server suite
Loading...
Searching...
No Matches
JobsHubGroupMapper.cs
Go to the documentation of this file.
1using System;
2using System.Collections.Generic;
3using System.Linq;
4using System.Threading;
5using System.Threading.Tasks;
6
7using Microsoft.AspNetCore.SignalR;
8using Microsoft.EntityFrameworkCore;
9using Microsoft.Extensions.Hosting;
10using Microsoft.Extensions.Logging;
11
17
19{
24 {
29
34
39
43 readonly ILogger<JobsHubGroupMapper> logger;
44
56 ILogger<JobsHubGroupMapper> logger)
57 {
58 this.hub = hub ?? throw new ArgumentNullException(nameof(hub));
59 this.databaseContextFactory = databaseContextFactory ?? throw new ArgumentNullException(nameof(databaseContextFactory));
60 this.jobsHubUpdater = jobsHubUpdater ?? throw new ArgumentNullException(nameof(jobsHubUpdater));
61 this.logger = logger ?? throw new ArgumentNullException(nameof(logger));
62
63 hub.OnConnectionMapGroups += MapConnectionGroups;
64 }
65
67 public ValueTask InstancePermissionSetCreated(InstancePermissionSet instancePermissionSet, CancellationToken cancellationToken)
68 {
69 ArgumentNullException.ThrowIfNull(instancePermissionSet);
70 var permissionSetId = instancePermissionSet.PermissionSetId;
71
72 logger.LogTrace("InstancePermissionSetCreated");
73 return RefreshHubGroups(
74 permissionSetId,
75 cancellationToken);
76 }
77
79 public ValueTask UserDisabled(User user, CancellationToken cancellationToken)
80 {
81 ArgumentNullException.ThrowIfNull(user);
82 if (!user.Id.HasValue)
83 throw new InvalidOperationException("user.Id was null!");
84
85 logger.LogTrace("UserDisabled");
86 hub.AbortUnauthedConnections(user);
87 return ValueTask.CompletedTask;
88 }
89
91 public ValueTask InstancePermissionSetDeleted(PermissionSet permissionSet, CancellationToken cancellationToken)
92 {
93 ArgumentNullException.ThrowIfNull(permissionSet);
94 logger.LogTrace("InstancePermissionSetDeleted");
95 return RefreshHubGroups(
96 permissionSet.Id ?? throw new InvalidOperationException("permissionSet?.Id was null!"),
97 cancellationToken);
98 }
99
101 public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
102
104 public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
105
113 async ValueTask MapConnectionGroups(
114 IAuthenticationContext authenticationContext,
115 Func<IEnumerable<string>, Task> mappingFunc,
116 CancellationToken cancellationToken)
117 {
118 ArgumentNullException.ThrowIfNull(authenticationContext);
119
120 var pid = authenticationContext.PermissionSet.Require(x => x.Id);
121 logger.LogTrace(
122 "MapConnectionGroups UID: {uid} PID: {pid}",
123 authenticationContext.User.Require(x => x.Id),
124 pid);
125
126 List<long>? permedInstanceIds = null;
128 async databaseContext =>
129 permedInstanceIds = await databaseContext
130 .InstancePermissionSets
131 .AsQueryable()
132 .Where(ips => ips.PermissionSetId == pid)
133 .Select(ips => ips.InstanceId)
134 .ToListAsync(cancellationToken));
135
136 await mappingFunc(
137 permedInstanceIds!.Select(
139
141 }
142
149 ValueTask RefreshHubGroups(long permissionSetId, CancellationToken cancellationToken)
151 async databaseContext =>
152 {
153 logger.LogTrace("RefreshHubGroups");
154 var permissionSetUsers = await databaseContext
155 .Users
156 .Where(x => x.PermissionSet!.Id == permissionSetId)
157 .ToListAsync(cancellationToken);
158 var allInstanceIds = await databaseContext
159 .Instances
160 .Select(
161 instance => instance.Id!.Value)
162 .ToListAsync(cancellationToken);
163 var permissionSetAccessibleInstanceIds = await databaseContext
164 .InstancePermissionSets
165 .AsQueryable()
166 .Where(ips => ips.PermissionSetId == permissionSetId)
167 .Select(ips => ips.InstanceId)
168 .ToListAsync(cancellationToken);
169
170 var groupsToRemove = allInstanceIds
171 .Except(permissionSetAccessibleInstanceIds)
172 .Select(JobsHub.HubGroupName);
173
174 var groupsToAdd = permissionSetAccessibleInstanceIds
175 .Select(JobsHub.HubGroupName);
176
177 var connectionIds = permissionSetUsers
178 .SelectMany(user => hub.UserConnectionIds(user))
179 .ToList();
180
181 logger.LogTrace(
182 "Updating groups for the {connectionCount} hub connections of permission set {permissionSetId}. They may access {allowed}/{total} instances.",
183 connectionIds.Count,
184 permissionSetId,
185 permissionSetAccessibleInstanceIds.Count,
186 allInstanceIds.Count);
187
188 var removeTasks = connectionIds
189 .SelectMany(connectionId => groupsToRemove
190 .Select(groupName => hub
191 .Groups
192 .RemoveFromGroupAsync(connectionId, groupName, cancellationToken)));
193
194 var addTasks = connectionIds
195 .SelectMany(connectionId => groupsToAdd
196 .Select(groupName => hub
197 .Groups
198 .AddToGroupAsync(connectionId, groupName, cancellationToken)));
199
200 // Checked internally, the default implementations for these tasks complete synchronously
201 // https://github.com/dotnet/aspnetcore/blob/ce330d9d12f7676ff35c2223bd8a3b1e252a4e86/src/SignalR/server/Core/src/DefaultHubLifetimeManager.cs#L34-L70
202 await Task.WhenAll(removeTasks.Concat(addTasks));
203 });
204 }
205}
virtual ? long Id
The ID of the entity.
Definition EntityId.cs:13
long PermissionSetId
The EntityId.Id of the PermissionSet the InstancePermissionSet belongs to.
Handles mapping groups for the JobsHub.
readonly IDatabaseContextFactory databaseContextFactory
The IDatabaseContextFactory for the JobService.
JobsHubGroupMapper(IConnectionMappedHubContext< JobsHub, IJobsHub > hub, IDatabaseContextFactory databaseContextFactory, IJobsHubUpdater jobsHubUpdater, ILogger< JobsHubGroupMapper > logger)
Initializes a new instance of the JobsHubGroupMapper class.
ValueTask UserDisabled(User user, CancellationToken cancellationToken)
Called when a given User is successfully disabled.A ValueTask representing the running operation.
readonly ILogger< JobsHubGroupMapper > logger
The ILogger for the JobService.
ValueTask InstancePermissionSetCreated(InstancePermissionSet instancePermissionSet, CancellationToken cancellationToken)
Called when a given instancePermissionSet is successfully created.A ValueTask representing the runni...
ValueTask InstancePermissionSetDeleted(PermissionSet permissionSet, CancellationToken cancellationToken)
Called when an InstancePermissionSet is successfully deleted.A ValueTask representing the running ope...
async ValueTask MapConnectionGroups(IAuthenticationContext authenticationContext, Func< IEnumerable< string >, Task > mappingFunc, CancellationToken cancellationToken)
Implementation of IConnectionMappedHubContext<THub, THubMethods>.OnConnectionMapGroups.
Task StopAsync(CancellationToken cancellationToken)
readonly IJobsHubUpdater jobsHubUpdater
The IJobsHubUpdater for the JobService.
readonly IConnectionMappedHubContext< JobsHub, IJobsHub > hub
The IHubContext for the JobsHub.
ValueTask RefreshHubGroups(long permissionSetId, CancellationToken cancellationToken)
Refresh the hub Hub.Groups for clients associated with a given permissionSetId .
Task StartAsync(CancellationToken cancellationToken)
A SignalR Hub for pushing job updates.
Definition JobsHub.cs:16
static string HubGroupName(long instanceId)
Get the group name for a given instanceId .
Factory for scoping usage of IDatabaseContexts. Meant for use by Components.
ValueTask UseContext(Func< IDatabaseContext, ValueTask > operation)
Run an operation in the scope of an IDatabaseContext.
Allows manually triggering jobs hub updates.
void QueueActiveJobUpdates()
Queue a message to be sent to all clients with the current state of active jobs.
For creating and accessing authentication contexts.
PermissionSet PermissionSet
The User's effective PermissionSet.
Receives notifications about permissions updates.
A IHubContext<THub> that maps Users to their connection IDs.