tgstation-server 6.19.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 .Where(ips => ips.PermissionSetId == pid)
132 .Select(ips => ips.InstanceId)
133 .ToListAsync(cancellationToken));
134
135 await mappingFunc(
136 permedInstanceIds!.Select(
138
140 }
141
148 ValueTask RefreshHubGroups(long permissionSetId, CancellationToken cancellationToken)
150 async databaseContext =>
151 {
152 logger.LogTrace("RefreshHubGroups");
153 var permissionSetUsers = await databaseContext
154 .Users
155 .Where(x => x.PermissionSet!.Id == permissionSetId)
156 .ToListAsync(cancellationToken);
157 var allInstanceIds = await databaseContext
158 .Instances
159 .Select(
160 instance => instance.Id!.Value)
161 .ToListAsync(cancellationToken);
162 var permissionSetAccessibleInstanceIds = await databaseContext
163 .InstancePermissionSets
164 .Where(ips => ips.PermissionSetId == permissionSetId)
165 .Select(ips => ips.InstanceId)
166 .ToListAsync(cancellationToken);
167
168 var groupsToRemove = allInstanceIds
169 .Except(permissionSetAccessibleInstanceIds)
170 .Select(JobsHub.HubGroupName);
171
172 var groupsToAdd = permissionSetAccessibleInstanceIds
173 .Select(JobsHub.HubGroupName);
174
175 var connectionIds = permissionSetUsers
176 .SelectMany(user => hub.UserConnectionIds(user))
177 .ToList();
178
179 logger.LogTrace(
180 "Updating groups for the {connectionCount} hub connections of permission set {permissionSetId}. They may access {allowed}/{total} instances.",
181 connectionIds.Count,
182 permissionSetId,
183 permissionSetAccessibleInstanceIds.Count,
184 allInstanceIds.Count);
185
186 var removeTasks = connectionIds
187 .SelectMany(connectionId => groupsToRemove
188 .Select(groupName => hub
189 .Groups
190 .RemoveFromGroupAsync(connectionId, groupName, cancellationToken)));
191
192 var addTasks = connectionIds
193 .SelectMany(connectionId => groupsToAdd
194 .Select(groupName => hub
195 .Groups
196 .AddToGroupAsync(connectionId, groupName, cancellationToken)));
197
198 // Checked internally, the default implementations for these tasks complete synchronously
199 // https://github.com/dotnet/aspnetcore/blob/ce330d9d12f7676ff35c2223bd8a3b1e252a4e86/src/SignalR/server/Core/src/DefaultHubLifetimeManager.cs#L34-L70
200 await Task.WhenAll(removeTasks.Concat(addTasks));
201 });
202 }
203}
virtual ? long Id
The ID of the entity.
Definition EntityId.cs:14
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.