mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-07-19 03:53:02 +01:00
Merge branch 'dev' into V6
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<!-- This is in it's own file to help incremental building, changing it causes a complete rebuild of the web panel -->
|
||||
<TgsControlPanelVersion>4.26.0</TgsControlPanelVersion>
|
||||
<TgsControlPanelVersion>4.26.2</TgsControlPanelVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@
|
||||
<TgsApiVersion>10.0.0</TgsApiVersion>
|
||||
<TgsCommonLibraryVersion>7.0.0</TgsCommonLibraryVersion>
|
||||
<TgsApiLibraryVersion>13.0.0</TgsApiLibraryVersion>
|
||||
<TgsClientVersion>16.0.0</TgsClientVersion>
|
||||
<TgsClientVersion>15.0.0</TgsClientVersion>
|
||||
<TgsDmapiVersion>6.6.2</TgsDmapiVersion>
|
||||
<TgsInteropVersion>5.6.2</TgsInteropVersion>
|
||||
<TgsHostWatchdogVersion>1.4.0</TgsHostWatchdogVersion>
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<!-- Usage: HTTP constants reference -->
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
|
||||
<!-- Usage: Decoding the 'nbf' property of JWTs -->
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.0.2" />
|
||||
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="7.0.3" />
|
||||
<!-- Usage: Primary JSON library -->
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
<!-- Usage: Data model annotating -->
|
||||
|
||||
@@ -372,13 +372,15 @@ namespace Tgstation.Server.Client
|
||||
|
||||
retryPolicy ??= new InfiniteThirtySecondMaxRetryPolicy();
|
||||
|
||||
var wrappedPolicy = new ApiClientTokenRefreshRetryPolicy(this, retryPolicy);
|
||||
|
||||
HubConnection? hubConnection = null;
|
||||
var hubConnectionBuilder = new HubConnectionBuilder()
|
||||
.AddNewtonsoftJsonProtocol(options =>
|
||||
{
|
||||
options.PayloadSerializerSettings = SerializerSettings;
|
||||
})
|
||||
.WithAutomaticReconnect(retryPolicy)
|
||||
.WithAutomaticReconnect(wrappedPolicy)
|
||||
.WithUrl(
|
||||
new Uri(Url, Routes.JobsHub),
|
||||
HttpTransportType.ServerSentEvents,
|
||||
@@ -480,6 +482,9 @@ namespace Tgstation.Server.Client
|
||||
if (content == null && (method == HttpMethod.Post || method == HttpMethod.Put))
|
||||
throw new InvalidOperationException("content cannot be null for POST or PUT!");
|
||||
|
||||
if (disposed)
|
||||
throw new ObjectDisposedException(nameof(ApiClient));
|
||||
|
||||
HttpResponseMessage response;
|
||||
var fullUri = new Uri(Url, route);
|
||||
var serializerSettings = SerializerSettings;
|
||||
|
||||
@@ -0,0 +1,61 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
using Microsoft.AspNetCore.SignalR.Client;
|
||||
|
||||
namespace Tgstation.Server.Client
|
||||
{
|
||||
/// <summary>
|
||||
/// A <see cref="IRetryPolicy"/> that attempts to refresh a given <see cref="apiClient"/>'s token on the first disconnect.
|
||||
/// </summary>
|
||||
sealed class ApiClientTokenRefreshRetryPolicy : IRetryPolicy
|
||||
{
|
||||
/// <summary>
|
||||
/// The backing <see cref="ApiClient"/>.
|
||||
/// </summary>
|
||||
readonly ApiClient apiClient;
|
||||
|
||||
/// <summary>
|
||||
/// The wrapped <see cref="IRetryPolicy"/>.
|
||||
/// </summary>
|
||||
readonly IRetryPolicy wrappedPolicy;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApiClientTokenRefreshRetryPolicy"/> class.
|
||||
/// </summary>
|
||||
/// <param name="apiClient">The value of <see cref="apiClient"/>.</param>
|
||||
/// <param name="wrappedPolicy">The value of <see cref="wrappedPolicy"/>.</param>
|
||||
public ApiClientTokenRefreshRetryPolicy(ApiClient apiClient, IRetryPolicy wrappedPolicy)
|
||||
{
|
||||
this.apiClient = apiClient ?? throw new ArgumentNullException(nameof(apiClient));
|
||||
this.wrappedPolicy = wrappedPolicy ?? throw new ArgumentNullException(nameof(wrappedPolicy));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public TimeSpan? NextRetryDelay(RetryContext retryContext)
|
||||
{
|
||||
if (retryContext == null)
|
||||
throw new ArgumentNullException(nameof(retryContext));
|
||||
|
||||
if (retryContext.PreviousRetryCount == 0)
|
||||
AttemptTokenRefresh();
|
||||
|
||||
return wrappedPolicy.NextRetryDelay(retryContext);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempt to refresh the <see cref="apiClient"/>s token asynchronously.
|
||||
/// </summary>
|
||||
async void AttemptTokenRefresh()
|
||||
{
|
||||
try
|
||||
{
|
||||
await apiClient.RefreshToken(CancellationToken.None);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// intentionally ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -403,7 +403,9 @@ namespace Tgstation.Server.Host.Core
|
||||
services.AddSingleton<IJobService>(provider => provider.GetRequiredService<JobService>());
|
||||
services.AddSingleton<IJobsHubUpdater>(provider => provider.GetRequiredService<JobService>());
|
||||
services.AddSingleton<IJobManager>(x => x.GetRequiredService<IJobService>());
|
||||
services.AddSingleton<IPermissionsUpdateNotifyee, JobsHubGroupMapper>();
|
||||
services.AddSingleton<JobsHubGroupMapper>();
|
||||
services.AddSingleton<IPermissionsUpdateNotifyee>(provider => provider.GetRequiredService<JobsHubGroupMapper>());
|
||||
services.AddSingleton<IHostedService>(x => x.GetRequiredService<JobsHubGroupMapper>()); // bit of a hack, but we need this to load immediated
|
||||
|
||||
services.AddSingleton<InstanceManager>();
|
||||
services.AddSingleton<IBridgeDispatcher>(x => x.GetRequiredService<InstanceManager>());
|
||||
|
||||
@@ -6,6 +6,7 @@ using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.AspNetCore.SignalR;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Tgstation.Server.Api.Hubs;
|
||||
@@ -19,7 +20,7 @@ namespace Tgstation.Server.Host.Jobs
|
||||
/// <summary>
|
||||
/// Handles mapping groups for the <see cref="JobsHub"/>.
|
||||
/// </summary>
|
||||
sealed class JobsHubGroupMapper : IPermissionsUpdateNotifyee
|
||||
sealed class JobsHubGroupMapper : IPermissionsUpdateNotifyee, IHostedService
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="IHubContext"/> for the <see cref="JobsHub"/>.
|
||||
@@ -96,6 +97,12 @@ namespace Tgstation.Server.Host.Jobs
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task StartAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task StopAsync(CancellationToken cancellationToken) => Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Implementation of <see cref="IConnectionMappedHubContext{THub, THubMethods}.OnConnectionMapGroups"/>.
|
||||
/// </summary>
|
||||
|
||||
@@ -83,12 +83,13 @@ namespace Tgstation.Server.Host.Utils.SignalR
|
||||
userId,
|
||||
context.ConnectionId);
|
||||
|
||||
var mappingTask = OnConnectionMapGroups(
|
||||
var mappingTask = OnConnectionMapGroups?.Invoke(
|
||||
authenticationContext,
|
||||
mappedGroups => Task.WhenAll(
|
||||
mappedGroups.Select(
|
||||
group => hub.Groups.AddToGroupAsync(context.ConnectionId, group, cancellationToken))),
|
||||
cancellationToken);
|
||||
cancellationToken)
|
||||
?? ValueTask.CompletedTask;
|
||||
userConnections.AddOrUpdate(
|
||||
userId,
|
||||
_ => new Dictionary<string, HubCallerContext>
|
||||
|
||||
Reference in New Issue
Block a user