Add CultMesh document registry helpers
This commit is contained in:
parent
39e13fdb3c
commit
c45a11e2c8
3 changed files with 184 additions and 0 deletions
111
src/GameCult.Mesh/CultMeshDocumentRegistries.cs
Normal file
111
src/GameCult.Mesh/CultMeshDocumentRegistries.cs
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using GameCult.Caching;
|
||||
using GameCult.Networking;
|
||||
|
||||
namespace GameCult.Mesh
|
||||
{
|
||||
public static partial class CultMesh
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a CultCache document registry and resolves the supplied document types into it.
|
||||
/// </summary>
|
||||
public static CultDocumentRegistry CreateCultCacheDocumentRegistry(params Type[] documentTypes)
|
||||
{
|
||||
return CreateCultCacheDocumentRegistry((IEnumerable<Type>)documentTypes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CultCache document registry and resolves the supplied document types into it.
|
||||
/// </summary>
|
||||
public static CultDocumentRegistry CreateCultCacheDocumentRegistry(IEnumerable<Type> documentTypes)
|
||||
{
|
||||
if (documentTypes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentTypes));
|
||||
}
|
||||
|
||||
var registry = new CultDocumentRegistry();
|
||||
foreach (var documentType in DistinctDocumentTypes(documentTypes))
|
||||
{
|
||||
registry.GetRequired(documentType);
|
||||
}
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CultNet document registry with default bindings for the supplied document types.
|
||||
/// </summary>
|
||||
public static CultNetDocumentRegistry CreateCultNetDocumentRegistry(params Type[] documentTypes)
|
||||
{
|
||||
return CreateCultNetDocumentRegistry((IEnumerable<Type>)documentTypes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CultNet document registry with default bindings for the supplied document types.
|
||||
/// </summary>
|
||||
public static CultNetDocumentRegistry CreateCultNetDocumentRegistry(IEnumerable<Type> documentTypes)
|
||||
{
|
||||
return CreateCultNetDocumentRegistry(documentTypes, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CultNet document registry with default bindings for the supplied document types.
|
||||
/// </summary>
|
||||
public static CultNetDocumentRegistry CreateCultNetDocumentRegistry(
|
||||
IEnumerable<Type> documentTypes,
|
||||
CultDocumentRegistry? documents)
|
||||
{
|
||||
if (documentTypes == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentTypes));
|
||||
}
|
||||
|
||||
documents ??= CreateCultCacheDocumentRegistry(documentTypes);
|
||||
var registry = new CultNetDocumentRegistry(documents);
|
||||
var descriptors = DistinctDocumentTypes(documentTypes)
|
||||
.Select(documentType => documents.GetRequired(documentType))
|
||||
.ToArray();
|
||||
foreach (var descriptorGroup in descriptors.GroupBy(descriptor => descriptor.SchemaId, StringComparer.Ordinal))
|
||||
{
|
||||
foreach (var descriptor in descriptorGroup.Reverse())
|
||||
{
|
||||
registry.Register(CultNetDocumentBinding.ForDocument(descriptor.DocumentType, documents));
|
||||
}
|
||||
}
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CultNet document registry with default bindings for the supplied document types.
|
||||
/// </summary>
|
||||
public static CultNetDocumentRegistry CreateCultNetDocumentRegistry(
|
||||
CultDocumentRegistry documents,
|
||||
params Type[] documentTypes)
|
||||
{
|
||||
return CreateCultNetDocumentRegistry(documentTypes, documents);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a CultNet document registry with default bindings for the supplied document types.
|
||||
/// </summary>
|
||||
public static CultNetDocumentRegistry CreateCultNetDocumentRegistry(
|
||||
CultDocumentRegistry documents,
|
||||
IEnumerable<Type> documentTypes)
|
||||
{
|
||||
return CreateCultNetDocumentRegistry(documentTypes, documents);
|
||||
}
|
||||
|
||||
private static IEnumerable<Type> DistinctDocumentTypes(IEnumerable<Type> documentTypes)
|
||||
{
|
||||
return documentTypes
|
||||
.Select(documentType => documentType ?? throw new ArgumentException(
|
||||
"Document type collections cannot contain null entries.",
|
||||
nameof(documentTypes)))
|
||||
.Distinct();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -94,6 +94,42 @@ namespace GameCult.Networking
|
|||
? payloadDeserializer(payload)
|
||||
: CultDocumentMessagePackSerialization.Deserialize<T>(payload));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a document binding for a CultCache document type discovered at runtime.
|
||||
/// </summary>
|
||||
public static CultNetDocumentBinding ForDocument(
|
||||
Type documentType,
|
||||
CultDocumentRegistry? registry = null,
|
||||
string? schemaId = null,
|
||||
Func<object, byte[]>? payloadSerializer = null,
|
||||
Func<byte[], object>? payloadDeserializer = null)
|
||||
{
|
||||
if (documentType == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(documentType));
|
||||
}
|
||||
|
||||
var descriptor = (registry ?? CultDocumentRegistry.Shared).GetRequired(documentType);
|
||||
return new CultNetDocumentBinding(
|
||||
documentType,
|
||||
string.IsNullOrWhiteSpace(schemaId) ? descriptor.SchemaId : schemaId!,
|
||||
document =>
|
||||
{
|
||||
if (!documentType.IsInstanceOfType(document))
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
$"Document payload type {document.GetType().FullName} is not assignable to {documentType.FullName}.");
|
||||
}
|
||||
|
||||
return payloadSerializer != null
|
||||
? payloadSerializer(document)
|
||||
: CultDocumentMessagePackSerialization.SerializeUntyped(document, documentType);
|
||||
},
|
||||
payload => payloadDeserializer != null
|
||||
? payloadDeserializer(payload)
|
||||
: CultDocumentMessagePackSerialization.DeserializeUntyped(documentType, payload));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -1101,6 +1101,43 @@ public sealed class CultMeshStreamingTests
|
|||
request.MessageId.StartsWith("mesh-test-scoped-snapshot:", StringComparison.Ordinal));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task DocumentRegistryHelpers_CreateTypedNetworkRegistriesForAliases()
|
||||
{
|
||||
var sourceCache = new CultCache();
|
||||
var cacheRegistry = CultMesh.CreateCultCacheDocumentRegistry(
|
||||
typeof(MeshNoteDocument),
|
||||
typeof(MeshNoteAliasDocument));
|
||||
var networkRegistry = CultMesh.CreateCultNetDocumentRegistry(
|
||||
new[] { typeof(MeshNoteDocument), typeof(MeshNoteAliasDocument) },
|
||||
cacheRegistry);
|
||||
var key = new CultRecordKey("mesh-note:registry-helper");
|
||||
await sourceCache.UpsertAsync(new MeshNoteDocument
|
||||
{
|
||||
Schema = "tests.mesh_note.v1",
|
||||
Text = "registry-helper",
|
||||
Revision = 23
|
||||
}, new CultRecordHandle<MeshNoteDocument>(key));
|
||||
var endpoint = "cultnet://registry-helper.test:3077";
|
||||
|
||||
var documents = await CultMesh.FetchSnapshotDocumentsAsync<MeshNoteAliasDocument>(
|
||||
endpoint,
|
||||
new CultMeshSnapshotRequestOptions
|
||||
{
|
||||
RecordKeys = new[] { key.Value },
|
||||
CreateClient = () => new MeshSnapshotSchemaClient(request =>
|
||||
networkRegistry.CreateRawSnapshotResponse(sourceCache, request.MessageId, request))
|
||||
},
|
||||
networkRegistry);
|
||||
|
||||
var schemaId = cacheRegistry.GetRequired<MeshNoteDocument>().SchemaId;
|
||||
cacheRegistry.GetRequired<MeshNoteAliasDocument>().SchemaId.Should().Be(schemaId);
|
||||
networkRegistry.GetByDocumentType(typeof(MeshNoteDocument)).Should().NotBeNull();
|
||||
networkRegistry.GetByDocumentType(typeof(MeshNoteAliasDocument)).Should().NotBeNull();
|
||||
networkRegistry.GetBySchemaId(schemaId)!.DocumentType.Should().Be(typeof(MeshNoteDocument));
|
||||
documents.Should().ContainSingle().Which.Text.Should().Be("registry-helper");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public async Task SnapshotEndpoint_ProvidesTypedHandlesAndSchemaAliases()
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in a new issue