Fix S.T.Json holding integration instances live for long. (#13080)

This commit is contained in:
Pieter-Jan Briers
2022-12-19 03:09:50 +01:00
committed by GitHub
parent 4bfc644a03
commit 896ffec8d9
6 changed files with 36 additions and 4 deletions

View File

@@ -24,6 +24,7 @@ public sealed partial class AdminLogManager
foreach (var converter in _reflection.FindTypesWithAttribute<AdminLogConverterAttribute>())
{
var instance = _typeFactory.CreateInstance<JsonConverter>(converter);
(instance as IAdminLogConverter)?.Init(_dependencies);
_jsonOptions.Converters.Add(instance);
}

View File

@@ -24,6 +24,7 @@ public sealed partial class AdminLogManager : SharedAdminLogManager, IAdminLogMa
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly IDynamicTypeFactory _typeFactory = default!;
[Dependency] private readonly IReflectionManager _reflection = default!;
[Dependency] private readonly IDependencyCollection _dependencies = default!;
public const string SawmillId = "admin.logs";

View File

@@ -3,8 +3,17 @@ using System.Text.Json.Serialization;
namespace Content.Server.Administration.Logs.Converters;
public abstract class AdminLogConverter<T> : JsonConverter<T>
public interface IAdminLogConverter
{
void Init(IDependencyCollection dependencies);
}
public abstract class AdminLogConverter<T> : JsonConverter<T>, IAdminLogConverter
{
public virtual void Init(IDependencyCollection dependencies)
{
}
public override T Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
throw new NotSupportedException();

View File

@@ -4,6 +4,7 @@ namespace Content.Server.Administration.Logs.Converters;
[AttributeUsage(AttributeTargets.Class)]
[BaseTypeRequired(typeof(AdminLogConverter<>))]
[MeansImplicitUse]
public sealed class AdminLogConverterAttribute : Attribute
{
}

View File

@@ -6,7 +6,14 @@ namespace Content.Server.Administration.Logs.Converters;
[AdminLogConverter]
public sealed class EntityUidConverter : AdminLogConverter<EntityUid>
{
[Dependency] private readonly IEntityManager _entities = default!;
// System.Text.Json actually keeps hold of your JsonSerializerOption instances in a cache on .NET 7.
// Use a weak reference to avoid holding server instances live too long in integration tests.
private WeakReference<IEntityManager> _entityManager = default!;
public override void Init(IDependencyCollection dependencies)
{
_entityManager = new WeakReference<IEntityManager>(dependencies.Resolve<IEntityManager>());
}
public static void Write(Utf8JsonWriter writer, EntityUid value, JsonSerializerOptions options, IEntityManager entities)
{
@@ -29,6 +36,9 @@ public sealed class EntityUidConverter : AdminLogConverter<EntityUid>
public override void Write(Utf8JsonWriter writer, EntityUid value, JsonSerializerOptions options)
{
Write(writer, value, options, _entities);
if (!_entityManager.TryGetTarget(out var entityManager))
throw new InvalidOperationException("EntityManager got garbage collected!");
Write(writer, value, options, entityManager);
}
}

View File

@@ -6,13 +6,23 @@ namespace Content.Server.Administration.Logs.Converters;
[AdminLogConverter]
public sealed class PlayerSessionConverter : AdminLogConverter<SerializablePlayer>
{
// System.Text.Json actually keeps hold of your JsonSerializerOption instances in a cache on .NET 7.
// Use a weak reference to avoid holding server instances live too long in integration tests.
private WeakReference<IEntityManager> _entityManager = default!;
public override void Init(IDependencyCollection dependencies)
{
_entityManager = new WeakReference<IEntityManager>(dependencies.Resolve<IEntityManager>());
}
public override void Write(Utf8JsonWriter writer, SerializablePlayer value, JsonSerializerOptions options)
{
writer.WriteStartObject();
if (value.Player.AttachedEntity is {Valid: true} playerEntity)
{
var entityManager = IoCManager.Resolve<IEntityManager>();
if (!_entityManager.TryGetTarget(out var entityManager))
throw new InvalidOperationException("EntityManager got garbage collected!");
writer.WriteNumber("id", (int) value.Player.AttachedEntity);
writer.WriteString("name", entityManager.GetComponent<MetaDataComponent>(playerEntity).EntityName);