CultNetDatabaseServerOptions.RemoteWriteAuthority is asked once per received write, after the schema resolves and before the shard does; none configured refuses every remote write; an authority that throws refuses and is logged. A refusal applies, publishes, logs and forwards nothing. The host's own CultNetDatabase.ApplyPutAsync/ApplyDeleteAsync ask no remote authority. Existing server tests whose subject is not the grant pass a test-local granting authority. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1804 lines
79 KiB
C#
1804 lines
79 KiB
C#
using System;
|
|
using MessagePack;
|
|
|
|
namespace GameCult.Networking
|
|
{
|
|
/// <summary>
|
|
/// Shared wire-contract identifiers understood by the CultNet family.
|
|
/// </summary>
|
|
public static class CultNetWireContracts
|
|
{
|
|
/// <summary>
|
|
/// schema v0 contract identifier.
|
|
/// </summary>
|
|
public const string SchemaV0 = "cultnet.schema.v0";
|
|
/// <summary>
|
|
/// game cult networking v0 contract identifier.
|
|
/// </summary>
|
|
public const string GameCultNetworkingV0 = "gamecult.networking.v0";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Canonical schema-version strings for the modern CultNet message family.
|
|
/// </summary>
|
|
public static class CultNetSchemaVersions
|
|
{
|
|
/// <summary>
|
|
/// hello contract identifier.
|
|
/// </summary>
|
|
public const string Hello = "cultnet.hello.v0";
|
|
/// <summary>
|
|
/// login contract identifier.
|
|
/// </summary>
|
|
public const string Login = "cultnet.login.v0";
|
|
/// <summary>
|
|
/// register contract identifier.
|
|
/// </summary>
|
|
public const string Register = "cultnet.register.v0";
|
|
/// <summary>
|
|
/// verify contract identifier.
|
|
/// </summary>
|
|
public const string Verify = "cultnet.verify.v0";
|
|
/// <summary>
|
|
/// login success contract identifier.
|
|
/// </summary>
|
|
public const string LoginSuccess = "cultnet.login_success.v0";
|
|
/// <summary>
|
|
/// error contract identifier.
|
|
/// </summary>
|
|
public const string Error = "cultnet.error.v0";
|
|
/// <summary>
|
|
/// sample change name contract identifier.
|
|
/// </summary>
|
|
public const string SampleChangeName = "cultnet.sample.change_name.v0";
|
|
/// <summary>
|
|
/// sample chat contract identifier.
|
|
/// </summary>
|
|
public const string SampleChat = "cultnet.sample.chat.v0";
|
|
/// <summary>
|
|
/// Generic typed service operation request contract identifier.
|
|
/// </summary>
|
|
public const string OperationRequest = "cultnet.operation_request.v0";
|
|
/// <summary>
|
|
/// Generic typed service operation response contract identifier.
|
|
/// </summary>
|
|
public const string OperationResponse = "cultnet.operation_response.v0";
|
|
/// <summary>
|
|
/// document delete contract identifier.
|
|
/// </summary>
|
|
public const string DocumentDelete = "cultnet.document_delete.v0";
|
|
/// <summary>
|
|
/// document put raw contract identifier.
|
|
/// </summary>
|
|
public const string DocumentPutRaw = "cultnet.document_put_raw.v0";
|
|
/// <summary>
|
|
/// snapshot request contract identifier.
|
|
/// </summary>
|
|
public const string SnapshotRequest = "cultnet.snapshot_request.v0";
|
|
/// <summary>
|
|
/// snapshot response raw contract identifier.
|
|
/// </summary>
|
|
public const string SnapshotResponseRaw = "cultnet.snapshot_response_raw.v0";
|
|
/// <summary>
|
|
/// typed-selection snapshot request contract identifier (docs/cultnet-selection-cut.md).
|
|
/// </summary>
|
|
public const string SnapshotRequestV1 = "cultnet.snapshot_request.v1";
|
|
/// <summary>
|
|
/// typed-selection database subscription request contract identifier (docs/cultnet-selection-cut.md).
|
|
/// </summary>
|
|
public const string DatabaseSubscribeV1 = "cultnet.database_subscribe.v1";
|
|
/// <summary>
|
|
/// typed-selection snapshot response contract identifier (docs/cultnet-selection-cut.md).
|
|
/// </summary>
|
|
public const string SnapshotResponseRawV1 = "cultnet.snapshot_response_raw.v1";
|
|
/// <summary>
|
|
/// schema catalog request contract identifier.
|
|
/// </summary>
|
|
public const string SchemaCatalogRequest = "cultnet.schema_catalog_request.v0";
|
|
/// <summary>
|
|
/// schema catalog response contract identifier.
|
|
/// </summary>
|
|
public const string SchemaCatalogResponse = "cultnet.schema_catalog_response.v0";
|
|
/// <summary>
|
|
/// database subscription request contract identifier.
|
|
/// </summary>
|
|
public const string DatabaseSubscribe = "cultnet.database_subscribe.v0";
|
|
/// <summary>
|
|
/// database subscription cancel contract identifier.
|
|
/// </summary>
|
|
public const string DatabaseUnsubscribe = "cultnet.database_unsubscribe.v0";
|
|
/// <summary>
|
|
/// database subscription change contract identifier.
|
|
/// </summary>
|
|
public const string DatabaseChangeRaw = "cultnet.database_change_raw.v0";
|
|
/// <summary>
|
|
/// shard catalog request contract identifier.
|
|
/// </summary>
|
|
public const string ShardCatalogRequest = "cultnet.shard_catalog_request.v0";
|
|
/// <summary>
|
|
/// shard catalog response contract identifier.
|
|
/// </summary>
|
|
public const string ShardCatalogResponse = "cultnet.shard_catalog_response.v0";
|
|
/// <summary>
|
|
/// shard mutation log request contract identifier.
|
|
/// </summary>
|
|
public const string ShardLogRequest = "cultnet.shard_log_request.v0";
|
|
/// <summary>
|
|
/// shard mutation log response contract identifier.
|
|
/// </summary>
|
|
public const string ShardLogResponse = "cultnet.shard_log_response.v0";
|
|
/// <summary>
|
|
/// simulation observation gossip contract identifier.
|
|
/// </summary>
|
|
public const string SimulationObservation = "cultnet.simulation_observation.v0";
|
|
/// <summary>
|
|
/// simulation consensus candidate gossip contract identifier.
|
|
/// </summary>
|
|
public const string SimulationConsensusCandidate = "cultnet.simulation_consensus_candidate.v0";
|
|
/// <summary>
|
|
/// witness artifact bundle document contract identifier.
|
|
/// </summary>
|
|
public const string WitnessArtifactBundle = "cultnet.witness_artifact_bundle.v0";
|
|
/// <summary>
|
|
/// CultMesh Verse catalog request contract identifier.
|
|
/// </summary>
|
|
public const string VerseCatalogRequest = "cultmesh.verse_catalog_request.v0";
|
|
/// <summary>
|
|
/// CultMesh Verse catalog response contract identifier.
|
|
/// </summary>
|
|
public const string VerseCatalogResponse = "cultmesh.verse_catalog_response.v0";
|
|
/// <summary>CultMesh session identity request contract identifier.</summary>
|
|
public const string SessionOpen = "cultmesh.session_open.v2";
|
|
/// <summary>CultMesh verified session identity response contract identifier.</summary>
|
|
public const string SessionAccepted = "cultmesh.session_accepted.v2";
|
|
/// <summary>
|
|
/// CultMesh peer exchange request contract identifier.
|
|
/// </summary>
|
|
public const string PeerExchangeRequest = "cultmesh.peer_exchange_request.v0";
|
|
/// <summary>
|
|
/// CultMesh peer exchange response contract identifier.
|
|
/// </summary>
|
|
public const string PeerExchangeResponse = "cultmesh.peer_exchange_response.v0";
|
|
/// <summary>
|
|
/// CultMesh content chunk request contract identifier.
|
|
/// </summary>
|
|
public const string ContentChunkRequest = "cultmesh.content_chunk_request.v1";
|
|
/// <summary>
|
|
/// CultMesh content chunk response contract identifier.
|
|
/// </summary>
|
|
public const string ContentChunkResponse = "cultmesh.content_chunk_response.v1";
|
|
/// <summary>
|
|
/// CultMesh ephemeral body read request contract identifier.
|
|
/// </summary>
|
|
public const string BodyReadRequest = "cultmesh.body_read_request.v1";
|
|
/// <summary>
|
|
/// CultMesh ephemeral body read response contract identifier.
|
|
/// </summary>
|
|
public const string BodyReadResponse = "cultmesh.body_read_response.v1";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Mutation authority owner identifiers advertised through CultNet mutation contracts.
|
|
/// </summary>
|
|
public static class CultNetMutationAuthorities
|
|
{
|
|
/// <summary>
|
|
/// The document is inspectable but not writable through CultNet.
|
|
/// </summary>
|
|
public const string ReadOnly = "readOnly";
|
|
/// <summary>
|
|
/// The local human operator may submit the corresponding mutation intent.
|
|
/// </summary>
|
|
public const string LocalUser = "localUser";
|
|
/// <summary>
|
|
/// A coordinator-owned Epiphany control surface owns the mutation path.
|
|
/// </summary>
|
|
public const string Coordinator = "coordinator";
|
|
/// <summary>
|
|
/// The runtime itself may write this document directly.
|
|
/// </summary>
|
|
public const string Runtime = "runtime";
|
|
/// <summary>
|
|
/// The document should not be mutated through CultNet.
|
|
/// </summary>
|
|
public const string Denied = "denied";
|
|
}
|
|
|
|
/// <summary>
|
|
/// Declares how a document or surface may be inspected and mutated over CultNet.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetDocumentMutationContract
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the stable document type governed by this contract.
|
|
/// </summary>
|
|
[Key("documentType")] public string DocumentType { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the payload schema version when the contract governs a versioned document payload.
|
|
/// </summary>
|
|
[Key("payloadSchemaVersion")] public string? PayloadSchemaVersion { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the CultNet operations this document accepts.
|
|
/// </summary>
|
|
[Key("operations")] public string[] Operations { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets which actor is allowed to drive those operations.
|
|
/// </summary>
|
|
[Key("authority")] public string Authority { get; set; } = CultNetMutationAuthorities.ReadOnly;
|
|
/// <summary>
|
|
/// Gets or sets the intent document types a client may submit to request mutation.
|
|
/// </summary>
|
|
[Key("intentDocumentTypes")] public string[]? IntentDocumentTypes { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the receipt document types emitted after a successful mutation path.
|
|
/// </summary>
|
|
[Key("receiptDocumentTypes")] public string[]? ReceiptDocumentTypes { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets freeform notes that explain local mutation guardrails or posture.
|
|
/// </summary>
|
|
[Key("notes")] public string[]? Notes { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Marker interface for the explicit modern CultNet schema-v0 message family.
|
|
/// </summary>
|
|
public interface ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version carried by this message.
|
|
/// </summary>
|
|
string SchemaVersion { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet hello message used to announce a runtime and its supported contracts.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetHelloMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Hello;
|
|
/// <summary>
|
|
/// Gets or sets the runtime id.
|
|
/// </summary>
|
|
[Key("runtimeId")] public string RuntimeId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the runtime kind.
|
|
/// </summary>
|
|
[Key("runtimeKind")] public string RuntimeKind { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the agent id.
|
|
/// </summary>
|
|
[Key("agentId")] public string? AgentId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the role.
|
|
/// </summary>
|
|
[Key("role")] public string? Role { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the display name.
|
|
/// </summary>
|
|
[Key("displayName")] public string? DisplayName { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the supported document types.
|
|
/// </summary>
|
|
[Key("supportedDocumentTypes")] public string[]? SupportedDocumentTypes { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the supported mutation contracts.
|
|
/// </summary>
|
|
[Key("supportedMutationContracts")] public CultNetDocumentMutationContract[]? SupportedMutationContracts { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the supported message versions.
|
|
/// </summary>
|
|
[Key("supportedMessageVersions")] public string[]? SupportedMessageVersions { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the transport profiles advertised by this peer.
|
|
/// </summary>
|
|
[Key("transportProfiles")] public CultNetTransportProfile[]? TransportProfiles { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the supports schema catalog.
|
|
/// </summary>
|
|
[Key("supportsSchemaCatalog")] public bool SupportsSchemaCatalog { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes the transports a runtime can speak.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetTransportProfile
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = "cultnet.transport_profile.v0";
|
|
/// <summary>
|
|
/// Gets or sets the runtime id.
|
|
/// </summary>
|
|
[Key("runtimeId")] public string RuntimeId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the transport descriptors.
|
|
/// </summary>
|
|
[Key("transports")] public CultNetTransportDescriptor[] Transports { get; set; } = Array.Empty<CultNetTransportDescriptor>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes one transport endpoint.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetTransportDescriptor
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the transport id.
|
|
/// </summary>
|
|
[Key("transportId")] public string TransportId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the protocol name.
|
|
/// </summary>
|
|
[Key("protocol")] public string Protocol { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the host.
|
|
/// </summary>
|
|
[Key("host")] public string? Host { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the port.
|
|
/// </summary>
|
|
[Key("port")] public int? Port { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the path.
|
|
/// </summary>
|
|
[Key("path")] public string? Path { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the discovery group.
|
|
/// </summary>
|
|
[Key("discoveryGroup")] public string? DiscoveryGroup { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the wire contracts.
|
|
/// </summary>
|
|
[Key("wireContracts")] public string[]? WireContracts { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the transport reconnect policy, when the transport owns reconnect posture.
|
|
/// </summary>
|
|
[Key("reconnectPolicy")] public CultNetReconnectPolicy? ReconnectPolicy { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the channels.
|
|
/// </summary>
|
|
[Key("channels")] public CultNetTransportChannel[] Channels { get; set; } = Array.Empty<CultNetTransportChannel>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes one transport channel.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetTransportChannel
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the channel id.
|
|
/// </summary>
|
|
[Key("channelId")] public string ChannelId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the delivery semantics.
|
|
/// </summary>
|
|
[Key("delivery")] public string Delivery { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the ordering semantics.
|
|
/// </summary>
|
|
[Key("ordering")] public string Ordering { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the maximum payload bytes.
|
|
/// </summary>
|
|
[Key("maxPayloadBytes")] public int? MaxPayloadBytes { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the maximum fragment bytes.
|
|
/// </summary>
|
|
[Key("maxFragmentBytes")] public int? MaxFragmentBytes { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the maximum pending reliable packet count.
|
|
/// </summary>
|
|
[Key("maxPendingReliablePackets")] public int? MaxPendingReliablePackets { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet login request message.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetLoginMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Login;
|
|
/// <summary>
|
|
/// Gets or sets the nonce.
|
|
/// </summary>
|
|
[Key("nonce")] public string Nonce { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the auth.
|
|
/// </summary>
|
|
[Key("auth")] public string Auth { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the password.
|
|
/// </summary>
|
|
[Key("password")] public string Password { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet registration request message.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetRegisterMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Register;
|
|
/// <summary>
|
|
/// Gets or sets the nonce.
|
|
/// </summary>
|
|
[Key("nonce")] public string Nonce { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the email.
|
|
/// </summary>
|
|
[Key("email")] public string Email { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the password.
|
|
/// </summary>
|
|
[Key("password")] public string Password { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the name.
|
|
/// </summary>
|
|
[Key("name")] public string Name { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet session verification request message.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetVerifyMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Verify;
|
|
/// <summary>
|
|
/// Gets or sets the nonce.
|
|
/// </summary>
|
|
[Key("nonce")] public string Nonce { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the session.
|
|
/// </summary>
|
|
[Key("session")] public string Session { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message returned after successful session verification.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetLoginSuccessMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.LoginSuccess;
|
|
/// <summary>
|
|
/// Gets or sets the nonce.
|
|
/// </summary>
|
|
[Key("nonce")] public string Nonce { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the session.
|
|
/// </summary>
|
|
[Key("session")] public string Session { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet error response message.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetErrorMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.Error;
|
|
/// <summary>
|
|
/// Gets or sets the error.
|
|
/// </summary>
|
|
[Key("error")] public string Error { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets optional shard routing details for authority failures.
|
|
/// </summary>
|
|
[Key("routingHint")] public CultNetShardRoutingHint? RoutingHint { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the machine-readable refusal code (R-N), e.g. <c>selection_invalid</c>,
|
|
/// <c>cursor_stale</c>, <c>cursor_invalid</c>, <c>reference_outside_target</c>, <c>unowned_schema</c>, <c>write_not_authorized</c>. Additive to
|
|
/// <c>cultnet.error.v0</c>; a v0 peer that does not know this field ignores it.
|
|
/// </summary>
|
|
[Key("code")] public string? Code { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the code-specific structured detail (R-N). Additive to <c>cultnet.error.v0</c>.
|
|
/// </summary>
|
|
[Key("details")] public CultNetErrorDetails? Details { get; set; }
|
|
|
|
/// <summary>
|
|
/// Builds the wire error for a door refusal (R-N): code <c>selection_invalid</c>, details
|
|
/// <c>{ field, value }</c>.
|
|
/// </summary>
|
|
public static CultNetErrorMessage ForSelectionInvalid(CultNetSelectionInvalidException ex) =>
|
|
new CultNetErrorMessage
|
|
{
|
|
Error = $"selection_invalid: {ex.Message}",
|
|
Code = "selection_invalid",
|
|
Details = new CultNetErrorDetails { Field = ex.Field, Value = ex.Value }
|
|
};
|
|
|
|
/// <summary>
|
|
/// Builds the wire error for a write no shard owns: code <c>unowned_schema</c>, details <c>{ field: "schemaId", value }</c>.
|
|
/// </summary>
|
|
public static CultNetErrorMessage ForUnownedSchema(CultNetUnownedSchemaException ex) =>
|
|
new CultNetErrorMessage
|
|
{
|
|
Error = $"unowned_schema: {ex.Message}",
|
|
Code = "unowned_schema",
|
|
Details = new CultNetErrorDetails { Field = "schemaId", Value = ex.SchemaId }
|
|
};
|
|
|
|
/// <summary>
|
|
/// Builds the wire error for a peer write its authority refused: code <c>write_not_authorized</c>, details
|
|
/// <c>{ field: "recordKey", value }</c>.
|
|
/// </summary>
|
|
public static CultNetErrorMessage ForRemoteWriteRefused(CultNetRemoteWriteRequest request, string? reason) =>
|
|
new CultNetErrorMessage
|
|
{
|
|
Error = string.IsNullOrWhiteSpace(reason) ? "write_not_authorized" : $"write_not_authorized: {reason}",
|
|
Code = "write_not_authorized",
|
|
Details = new CultNetErrorDetails { Field = "recordKey", Value = request.RecordKey.Value }
|
|
};
|
|
|
|
/// <summary>
|
|
/// Builds the wire error for a cursor refusal (R-N): code <c>cursor_stale</c> with details
|
|
/// <c>{ asOf, current }</c>, or code <c>cursor_invalid</c> with no details.
|
|
/// </summary>
|
|
public static CultNetErrorMessage ForCursor(CultNetSelectionCursorException ex) =>
|
|
new CultNetErrorMessage
|
|
{
|
|
Error = $"{ex.Code}: {ex.Message}",
|
|
Code = ex.Code,
|
|
Details = ex.Code == "cursor_stale"
|
|
? new CultNetErrorDetails { AsOf = ex.AsOf, Current = ex.Current }
|
|
: null
|
|
};
|
|
|
|
/// <summary>
|
|
/// Builds the wire error for a selection that selects a document variant, which CultNet does not carry yet: code
|
|
/// <c>variant_unsupported</c>, details <c>{ field: "subscriptionId", value }</c> when a subscription was ended by it.
|
|
/// </summary>
|
|
public static CultNetErrorMessage ForVariantUnsupported(string message, string? subscriptionId = null) =>
|
|
new CultNetErrorMessage
|
|
{
|
|
Error = message,
|
|
Code = "variant_unsupported",
|
|
Details = subscriptionId == null ? null : new CultNetErrorDetails { Field = "subscriptionId", Value = subscriptionId }
|
|
};
|
|
|
|
/// <summary>
|
|
/// Builds the wire error for an out-of-target reference refusal (R-N): code
|
|
/// <c>reference_outside_target</c>, no details.
|
|
/// </summary>
|
|
public static CultNetErrorMessage ForReferenceOutsideTarget(CultNetSelectionReferenceOutsideTargetException ex) =>
|
|
new CultNetErrorMessage
|
|
{
|
|
// ex.Message already begins "reference_outside_target: " (the exception's own
|
|
// constructor prefixes it) - this used to prefix it a second time, so a peer received
|
|
// "reference_outside_target: reference_outside_target: ...". Rust's ForReferenceOutsideTarget
|
|
// (packages/cultnet-rs) emits the single-prefixed form; this now matches it.
|
|
Error = ex.Message,
|
|
Code = "reference_outside_target"
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Code-specific structured detail carried on <see cref="CultNetErrorMessage"/> (R-N). Fields are
|
|
/// populated only for the code that defines them; every field is otherwise omitted (nil on the wire).
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetErrorDetails
|
|
{
|
|
/// <summary>The selection field that failed (<c>selection_invalid</c>).</summary>
|
|
[Key("field")] public string? Field { get; set; }
|
|
/// <summary>The offending value, when there is one string worth naming (<c>selection_invalid</c>).</summary>
|
|
[Key("value")] public string? Value { get; set; }
|
|
/// <summary>The cursor's own minted asOf (<c>cursor_stale</c>).</summary>
|
|
[Key("asOf")] public ulong? AsOf { get; set; }
|
|
/// <summary>The answering server's current asOf (<c>cursor_stale</c>).</summary>
|
|
[Key("current")] public ulong? Current { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes where a shard write should be routed.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetShardRoutingHint
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the shard descriptor.
|
|
/// </summary>
|
|
[Key("shard")] public CultNetShardDescriptorMessage? Shard { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets a machine-readable routing reason.
|
|
/// </summary>
|
|
[Key("reason")] public string Reason { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sample CultNet message used by development clients to change a display name.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSampleChangeNameMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SampleChangeName;
|
|
/// <summary>
|
|
/// Gets or sets the name.
|
|
/// </summary>
|
|
[Key("name")] public string Name { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sample CultNet chat message used by development clients.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSampleChatMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SampleChat;
|
|
/// <summary>
|
|
/// Gets or sets the text.
|
|
/// </summary>
|
|
[Key("text")] public string Text { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Invokes one typed operation on an advertised service.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetOperationRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>Gets or sets the wire schema version.</summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.OperationRequest;
|
|
/// <summary>Gets or sets the correlation id.</summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the advertised service id.</summary>
|
|
[Key("serviceId")] public string ServiceId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the requested operation.</summary>
|
|
[Key("operation")] public string Operation { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the inner payload schema.</summary>
|
|
[Key("payloadSchema")] public string PayloadSchema { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the inner payload encoding.</summary>
|
|
[Key("payloadEncoding")] public string PayloadEncoding { get; set; } = "messagepack-base64";
|
|
/// <summary>Gets or sets the encoded inner payload.</summary>
|
|
[Key("payload")] public string Payload { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the calling runtime id.</summary>
|
|
[Key("sourceRuntimeId")] public string? SourceRuntimeId { get; set; }
|
|
/// <summary>Gets or sets an optional target runtime id.</summary>
|
|
[Key("targetRuntimeId")] public string? TargetRuntimeId { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns the correlated result of one typed service operation.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetOperationResponseMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>Gets or sets the wire schema version.</summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.OperationResponse;
|
|
/// <summary>Gets or sets the request correlation id.</summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the advertised service id.</summary>
|
|
[Key("serviceId")] public string ServiceId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the completed operation.</summary>
|
|
[Key("operation")] public string Operation { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the operation status.</summary>
|
|
[Key("status")] public string Status { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the inner payload schema.</summary>
|
|
[Key("payloadSchema")] public string PayloadSchema { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the inner payload encoding.</summary>
|
|
[Key("payloadEncoding")] public string PayloadEncoding { get; set; } = "messagepack-base64";
|
|
/// <summary>Gets or sets the encoded inner payload.</summary>
|
|
[Key("payload")] public string Payload { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets transport-level diagnostics.</summary>
|
|
[Key("diagnostics")] public string[] Diagnostics { get; set; } = Array.Empty<string>();
|
|
/// <summary>Gets or sets the responding runtime id.</summary>
|
|
[Key("sourceRuntimeId")] public string? SourceRuntimeId { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Raw document record carried over CultNet.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetRawDocumentRecord
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema id.
|
|
/// </summary>
|
|
[Key("schemaId")] public string SchemaId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the stable schema family name when the publisher has a typed descriptor.
|
|
/// </summary>
|
|
[Key("schemaName")] public string? SchemaName { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the portable versioned schema contract when the publisher has a typed descriptor.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string? SchemaVersion { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the canonical schema content hash when the publisher has a typed descriptor.
|
|
/// </summary>
|
|
[Key("schemaContentHash")] public string? SchemaContentHash { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the record key.
|
|
/// </summary>
|
|
[Key("recordKey")] public string RecordKey { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the stored at.
|
|
/// </summary>
|
|
[Key("storedAt")] public string StoredAt { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the payload encoding.
|
|
/// </summary>
|
|
[Key("payloadEncoding")] public string PayloadEncoding { get; set; } = "messagepack";
|
|
/// <summary>
|
|
/// Gets or sets the payload.
|
|
/// </summary>
|
|
[Key("payload")] public byte[] Payload { get; set; } = Array.Empty<byte>();
|
|
/// <summary>
|
|
/// Gets or sets the source runtime id.
|
|
/// </summary>
|
|
[Key("sourceRuntimeId")] public string? SourceRuntimeId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the source agent id.
|
|
/// </summary>
|
|
[Key("sourceAgentId")] public string? SourceAgentId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the source role.
|
|
/// </summary>
|
|
[Key("sourceRole")] public string? SourceRole { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the tags.
|
|
/// </summary>
|
|
[Key("tags")] public string[]? Tags { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message requesting deletion of a document record.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetDocumentDeleteMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DocumentDelete;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the schema id.
|
|
/// </summary>
|
|
[Key("schemaId")] public string SchemaId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the record key.
|
|
/// </summary>
|
|
[Key("recordKey")] public string RecordKey { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the shard id the sender targeted.
|
|
/// </summary>
|
|
[Key("shardId")] public string? ShardId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the shard epoch the sender targeted.
|
|
/// </summary>
|
|
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message carrying one raw document record.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetDocumentPutRawMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DocumentPutRaw;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the document.
|
|
/// </summary>
|
|
[Key("document")] public CultNetRawDocumentRecord Document { get; set; } = new CultNetRawDocumentRecord();
|
|
/// <summary>
|
|
/// Gets or sets the shard id the sender targeted.
|
|
/// </summary>
|
|
[Key("shardId")] public string? ShardId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the shard epoch the sender targeted.
|
|
/// </summary>
|
|
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message requesting a document snapshot.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSnapshotRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SnapshotRequest;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the schema ids.
|
|
/// </summary>
|
|
[Key("schemaIds")] public string[]? SchemaIds { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the record keys.
|
|
/// </summary>
|
|
[Key("recordKeys")] public string[]? RecordKeys { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the shard id requested for a shard-bounded snapshot.
|
|
/// </summary>
|
|
[Key("shardId")] public string? ShardId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the expected shard epoch.
|
|
/// </summary>
|
|
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message returning raw document records from a snapshot request.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSnapshotResponseRawMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SnapshotResponseRaw;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the documents.
|
|
/// </summary>
|
|
[Key("documents")] public CultNetRawDocumentRecord[] Documents { get; set; } = Array.Empty<CultNetRawDocumentRecord>();
|
|
/// <summary>
|
|
/// Gets or sets the shard id represented by this snapshot.
|
|
/// </summary>
|
|
[Key("shardId")] public string? ShardId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the shard epoch represented by this snapshot.
|
|
/// </summary>
|
|
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the shard-log sequence represented by this snapshot.
|
|
/// </summary>
|
|
[Key("shardLogSequence")] public long? ShardLogSequence { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Requests a live database subscription.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetDatabaseSubscribeMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DatabaseSubscribe;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the live subscription id.
|
|
/// </summary>
|
|
[Key("subscriptionId")] public string SubscriptionId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets optional schema ids to watch.
|
|
/// </summary>
|
|
[Key("schemaIds")] public string[]? SchemaIds { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets optional record keys to watch.
|
|
/// </summary>
|
|
[Key("recordKeys")] public string[]? RecordKeys { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets whether the server should send a matching snapshot before live changes.
|
|
/// </summary>
|
|
[Key("includeSnapshot")] public bool IncludeSnapshot { get; set; } = true;
|
|
/// <summary>
|
|
/// Gets or sets the stable consumer runtime identity used for subscription diagnostics and body-plane demand.
|
|
/// </summary>
|
|
[Key("consumerRuntimeId")] public string? ConsumerRuntimeId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets logical hot-body identities needed by this exact state subscription.
|
|
/// </summary>
|
|
[Key("bodyIds")] public string[]? BodyIds { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets body transports the consumer can open, ordered by consumer preference.
|
|
/// </summary>
|
|
[Key("supportedBodyTransports")] public string[]? SupportedBodyTransports { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message requesting a document snapshot through a typed selection (docs/cultnet-selection-cut.md).
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSnapshotRequestV1Message : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>Gets or sets the schema version.</summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SnapshotRequestV1;
|
|
/// <summary>Gets or sets the message id.</summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the selection.</summary>
|
|
[Key("selection")] public CultNetSelection Selection { get; set; } = new CultNetSelection();
|
|
/// <summary>Gets or sets the shard id requested for a shard-bounded snapshot.</summary>
|
|
[Key("shardId")] public string? ShardId { get; set; }
|
|
/// <summary>Gets or sets the expected shard epoch.</summary>
|
|
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Requests a live database subscription through a typed selection (docs/cultnet-selection-cut.md).
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetDatabaseSubscribeV1Message : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>Gets or sets the schema version.</summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DatabaseSubscribeV1;
|
|
/// <summary>Gets or sets the request id.</summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the live subscription id.</summary>
|
|
[Key("subscriptionId")] public string SubscriptionId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the selection.</summary>
|
|
[Key("selection")] public CultNetSelection Selection { get; set; } = new CultNetSelection();
|
|
/// <summary>Gets or sets whether the server should send a matching snapshot before live changes.</summary>
|
|
[Key("includeSnapshot")] public bool IncludeSnapshot { get; set; } = true;
|
|
/// <summary>Gets or sets the stable consumer runtime identity used for subscription diagnostics and body-plane demand.</summary>
|
|
[Key("consumerRuntimeId")] public string? ConsumerRuntimeId { get; set; }
|
|
/// <summary>Gets or sets logical hot-body identities needed by this exact state subscription.</summary>
|
|
[Key("bodyIds")] public string[]? BodyIds { get; set; }
|
|
/// <summary>Gets or sets body transports the consumer can open, ordered by consumer preference.</summary>
|
|
[Key("supportedBodyTransports")] public string[]? SupportedBodyTransports { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message returning a typed selection's page (docs/cultnet-selection-cut.md).
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSnapshotResponseRawV1Message : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>Gets or sets the schema version.</summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SnapshotResponseRawV1;
|
|
/// <summary>Gets or sets the message id.</summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the number of rows on this page.</summary>
|
|
[Key("matched")] public uint Matched { get; set; }
|
|
/// <summary>Gets or sets the snapshot this page is exact as of.</summary>
|
|
[Key("asOf")] public ulong AsOf { get; set; }
|
|
/// <summary>Gets or sets the cursor for the next page, absent on the last page.</summary>
|
|
[Key("next")] public string? Next { get; set; }
|
|
/// <summary>Gets or sets the headers, present under header projection.</summary>
|
|
[Key("headers")] public CultNetRawDocumentHeader[]? Headers { get; set; }
|
|
/// <summary>Gets or sets the documents, present under document projection.</summary>
|
|
[Key("documents")] public CultNetRawDocumentRecord[]? Documents { get; set; }
|
|
/// <summary>Gets or sets the edges a hop-bearing selection traversed.</summary>
|
|
[Key("edges")] public CultNetEdge[]? Edges { get; set; }
|
|
/// <summary>Gets or sets the shard id represented by this snapshot.</summary>
|
|
[Key("shardId")] public string? ShardId { get; set; }
|
|
/// <summary>Gets or sets the shard epoch represented by this snapshot.</summary>
|
|
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
|
|
/// <summary>Gets or sets the shard-log sequence represented by this snapshot.</summary>
|
|
[Key("shardLogSequence")] public long? ShardLogSequence { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Cancels a live database subscription.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetDatabaseUnsubscribeMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DatabaseUnsubscribe;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the live subscription id.
|
|
/// </summary>
|
|
[Key("subscriptionId")] public string SubscriptionId { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Streams one raw document change for a live database subscription.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetDatabaseChangeRawMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.DatabaseChangeRaw;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the live subscription id.
|
|
/// </summary>
|
|
[Key("subscriptionId")] public string SubscriptionId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the change kind.
|
|
/// </summary>
|
|
[Key("changeKind")] public string ChangeKind { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the current document for added or updated changes.
|
|
/// </summary>
|
|
[Key("document")] public CultNetRawDocumentRecord? Document { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the deleted record key for removed changes.
|
|
/// </summary>
|
|
[Key("recordKey")] public string? RecordKey { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the deleted schema id for removed changes.
|
|
/// </summary>
|
|
[Key("schemaId")] public string? SchemaId { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes one shard advertised by a CultNet database node.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetShardDescriptorMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the shard id.
|
|
/// </summary>
|
|
[Key("shardId")] public string ShardId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the owner runtime id.
|
|
/// </summary>
|
|
[Key("ownerRuntimeId")] public string OwnerRuntimeId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the shard authority epoch.
|
|
/// </summary>
|
|
[Key("epoch")] public long Epoch { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets whether the responding node is primary for this shard.
|
|
/// </summary>
|
|
[Key("isPrimary")] public bool IsPrimary { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets schema ids governed by this shard. Empty means all schemas.
|
|
/// </summary>
|
|
[Key("schemaIds")] public string[] SchemaIds { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets the record-key prefix governed by this shard.
|
|
/// </summary>
|
|
[Key("keyPrefix")] public string? KeyPrefix { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets endpoints that accept authoritative writes.
|
|
/// </summary>
|
|
[Key("primaryEndpoints")] public string[] PrimaryEndpoints { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets authoritative replica endpoints.
|
|
/// </summary>
|
|
[Key("replicaEndpoints")] public string[] ReplicaEndpoints { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets low-latency read replica endpoints.
|
|
/// </summary>
|
|
[Key("readReplicaEndpoints")] public string[] ReadReplicaEndpoints { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets an optional locality label.
|
|
/// </summary>
|
|
[Key("region")] public string? Region { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Requests shard ownership and routing metadata.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetShardCatalogRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ShardCatalogRequest;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets optional schema filters.
|
|
/// </summary>
|
|
[Key("schemaIds")] public string[]? SchemaIds { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets optional record-key filters.
|
|
/// </summary>
|
|
[Key("recordKeys")] public string[]? RecordKeys { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns shard ownership and routing metadata.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetShardCatalogResponseMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ShardCatalogResponse;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets shard descriptors.
|
|
/// </summary>
|
|
[Key("shards")] public CultNetShardDescriptorMessage[] Shards { get; set; } = Array.Empty<CultNetShardDescriptorMessage>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Requests accepted mutation log entries for a shard.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetShardLogRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ShardLogRequest;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the shard id.
|
|
/// </summary>
|
|
[Key("shardId")] public string ShardId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the shard epoch expected by the requester.
|
|
/// </summary>
|
|
[Key("shardEpoch")] public long? ShardEpoch { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the last sequence already held by the requester.
|
|
/// </summary>
|
|
[Key("afterSequence")] public long AfterSequence { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the maximum number of entries to return.
|
|
/// </summary>
|
|
[Key("limit")] public int? Limit { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns accepted mutation log entries for a shard.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetShardLogResponseMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ShardLogResponse;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the shard id.
|
|
/// </summary>
|
|
[Key("shardId")] public string ShardId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the shard epoch.
|
|
/// </summary>
|
|
[Key("shardEpoch")] public long ShardEpoch { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets mutation log entries.
|
|
/// </summary>
|
|
[Key("entries")] public CultNetShardLogEntryMessage[] Entries { get; set; } = Array.Empty<CultNetShardLogEntryMessage>();
|
|
/// <summary>
|
|
/// Gets or sets whether the requester must fall back to a shard snapshot.
|
|
/// </summary>
|
|
[Key("resyncRequired")] public bool ResyncRequired { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets a machine-readable resync reason.
|
|
/// </summary>
|
|
[Key("reason")] public string? Reason { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the highest sequence compacted out of the retained log.
|
|
/// </summary>
|
|
[Key("compactedThrough")] public long? CompactedThrough { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes one accepted shard mutation for replica catch-up.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetShardLogEntryMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the per-shard sequence.
|
|
/// </summary>
|
|
[Key("sequence")] public long Sequence { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the commit timestamp.
|
|
/// </summary>
|
|
[Key("committedAt")] public string CommittedAt { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the mutation kind.
|
|
/// </summary>
|
|
[Key("changeKind")] public string ChangeKind { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets a raw put message for added/updated entries.
|
|
/// </summary>
|
|
[Key("put")] public CultNetDocumentPutRawMessage? Put { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets a raw delete message for removed entries.
|
|
/// </summary>
|
|
[Key("delete")] public CultNetDocumentDeleteMessage? Delete { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Carries one witness observation about a simulation fact.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSimulationObservationMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SimulationObservation;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the observation.
|
|
/// </summary>
|
|
[Key("observation")] public CultNetSimulationObservation Observation { get; set; } = new CultNetSimulationObservation();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Carries one deterministic consensus candidate derived from witness observations.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSimulationConsensusCandidateMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SimulationConsensusCandidate;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the shard id.
|
|
/// </summary>
|
|
[Key("shardId")] public string ShardId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the shard epoch.
|
|
/// </summary>
|
|
[Key("shardEpoch")] public long ShardEpoch { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the simulation frame.
|
|
/// </summary>
|
|
[Key("frame")] public long Frame { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the subject id.
|
|
/// </summary>
|
|
[Key("subjectId")] public string SubjectId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the claim kind.
|
|
/// </summary>
|
|
[Key("claimKind")] public string ClaimKind { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the selected claim hash.
|
|
/// </summary>
|
|
[Key("claimHash")] public string ClaimHash { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets optional claim detail.
|
|
/// </summary>
|
|
[Key("claimSummary")] public string? ClaimSummary { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets distinct supporting witnesses.
|
|
/// </summary>
|
|
[Key("witnessCount")] public int WitnessCount { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets supporting witness weight.
|
|
/// </summary>
|
|
[Key("supportWeight")] public double SupportWeight { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets total observed witness weight.
|
|
/// </summary>
|
|
[Key("totalWeight")] public double TotalWeight { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets whether the candidate crossed quorum.
|
|
/// </summary>
|
|
[Key("hasQuorum")] public bool HasQuorum { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets support divided by total observed weight.
|
|
/// </summary>
|
|
[Key("confidence")] public double Confidence { get; set; }
|
|
|
|
/// <summary>
|
|
/// Creates a wire candidate message from a local candidate.
|
|
/// </summary>
|
|
public static CultNetSimulationConsensusCandidateMessage FromCandidate(
|
|
string messageId,
|
|
CultNetSimulationConsensusCandidate candidate)
|
|
{
|
|
if (candidate == null) throw new ArgumentNullException(nameof(candidate));
|
|
return new CultNetSimulationConsensusCandidateMessage
|
|
{
|
|
MessageId = string.IsNullOrWhiteSpace(messageId) ? Guid.NewGuid().ToString("N") : messageId,
|
|
ShardId = candidate.ShardId,
|
|
ShardEpoch = candidate.ShardEpoch,
|
|
Frame = candidate.Frame,
|
|
SubjectId = candidate.SubjectId,
|
|
ClaimKind = candidate.ClaimKind,
|
|
ClaimHash = candidate.ClaimHash,
|
|
ClaimSummary = candidate.ClaimSummary,
|
|
WitnessCount = candidate.WitnessCount,
|
|
SupportWeight = candidate.SupportWeight,
|
|
TotalWeight = candidate.TotalWeight,
|
|
HasQuorum = candidate.HasQuorum,
|
|
Confidence = candidate.Confidence
|
|
};
|
|
}
|
|
}
|
|
|
|
/// <summary>Requests an identity-bound CultMesh session before application traffic begins.</summary>
|
|
[MessagePackObject]
|
|
public class CultMeshSessionOpenMessage : ICultNetSchemaMessage
|
|
{
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SessionOpen;
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
[Key("sourceRuntimeId")] public string SourceRuntimeId { get; set; } = string.Empty;
|
|
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
|
|
[Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty;
|
|
[Key("protocolId")] public string ProtocolId { get; set; } = string.Empty;
|
|
[Key("routeGeneration")] public string RouteGeneration { get; set; } = string.Empty;
|
|
[Key("clientNonce")] public string ClientNonce { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>Accepts or rejects a CultMesh session with the server's actual identity.</summary>
|
|
[MessagePackObject]
|
|
public class CultMeshSessionAcceptedMessage : ICultNetSchemaMessage
|
|
{
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SessionAccepted;
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
[Key("accepted")] public bool Accepted { get; set; }
|
|
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
|
|
[Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty;
|
|
[Key("protocolId")] public string ProtocolId { get; set; } = string.Empty;
|
|
[Key("routeGeneration")] public string RouteGeneration { get; set; } = string.Empty;
|
|
[Key("clientNonce")] public string ClientNonce { get; set; } = string.Empty;
|
|
[Key("providerKeyId")] public string ProviderKeyId { get; set; } = string.Empty;
|
|
[Key("providerSignature")] public string ProviderSignature { get; set; } = string.Empty;
|
|
[Key("error")] public string? Error { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Requests known CultMesh Verses from a peer.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshVerseCatalogRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.VerseCatalogRequest;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets optional Verse ids to request.
|
|
/// </summary>
|
|
[Key("verseIds")] public string[]? VerseIds { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets an optional transport compatibility filter.
|
|
/// </summary>
|
|
[Key("transportVersion")] public string? TransportVersion { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns known CultMesh Verses.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshVerseCatalogResponseMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.VerseCatalogResponse;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets discovered Verses.
|
|
/// </summary>
|
|
[Key("verses")] public CultMeshVerseDescriptorMessage[] Verses { get; set; } = Array.Empty<CultMeshVerseDescriptorMessage>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Wire representation of a CultMesh Verse.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshVerseDescriptorMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the stable Verse id.
|
|
/// </summary>
|
|
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the display name.
|
|
/// </summary>
|
|
[Key("displayName")] public string DisplayName { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the authority model name.
|
|
/// </summary>
|
|
[Key("authorityModel")] public string AuthorityModel { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets compatibility metadata.
|
|
/// </summary>
|
|
[Key("compatibility")] public CultMeshVerseCompatibilityMessage Compatibility { get; set; } = new CultMeshVerseCompatibilityMessage();
|
|
/// <summary>
|
|
/// Gets or sets endpoints that can answer discovery for this Verse.
|
|
/// </summary>
|
|
[Key("discoveryEndpoints")] public string[] DiscoveryEndpoints { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets known authoritative runtime ids.
|
|
/// </summary>
|
|
[Key("authorityRuntimeIds")] public string[] AuthorityRuntimeIds { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets exact authoritative-runtime route bindings. This is the
|
|
/// routing authority; the parallel legacy arrays are projections only.
|
|
/// </summary>
|
|
[Key("authorityRoutes")] public CultMeshAuthorityRouteMessage[] AuthorityRoutes { get; set; } = Array.Empty<CultMeshAuthorityRouteMessage>();
|
|
/// <summary>
|
|
/// Gets or sets the parent Verse id for overlays or branches.
|
|
/// </summary>
|
|
[Key("parentVerseId")] public string? ParentVerseId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets an optional public description.
|
|
/// </summary>
|
|
[Key("description")] public string? Description { get; set; }
|
|
}
|
|
|
|
/// <summary>Wire representation of one authority-bound CultMesh route.</summary>
|
|
[MessagePackObject]
|
|
public class CultMeshAuthorityRouteMessage
|
|
{
|
|
[Key("authorityRuntimeId")] public string AuthorityRuntimeId { get; set; } = string.Empty;
|
|
[Key("endpoint")] public string Endpoint { get; set; } = string.Empty;
|
|
[Key("protocolIds")] public string[] ProtocolIds { get; set; } = Array.Empty<string>();
|
|
[Key("priority")] public int Priority { get; set; }
|
|
[Key("generation")] public string Generation { get; set; } = string.Empty;
|
|
[Key("certificate")] public CultMeshRouteCertificateMessage? Certificate { get; set; }
|
|
}
|
|
|
|
[MessagePackObject]
|
|
public class CultMeshRouteCertificateMessage
|
|
{
|
|
[Key("providerKeyId")] public string ProviderKeyId { get; set; } = string.Empty;
|
|
[Key("providerPublicKeyX")] public string ProviderPublicKeyX { get; set; } = string.Empty;
|
|
[Key("providerPublicKeyY")] public string ProviderPublicKeyY { get; set; } = string.Empty;
|
|
[Key("odinKeyId")] public string OdinKeyId { get; set; } = string.Empty;
|
|
[Key("issuedAtUnixMilliseconds")] public long IssuedAtUnixMilliseconds { get; set; }
|
|
[Key("expiresAtUnixMilliseconds")] public long ExpiresAtUnixMilliseconds { get; set; }
|
|
[Key("signature")] public string Signature { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Wire representation of CultMesh Verse compatibility.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshVerseCompatibilityMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the CultMesh transport compatibility version.
|
|
/// </summary>
|
|
[Key("transportVersion")] public string TransportVersion { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the stable rules hash.
|
|
/// </summary>
|
|
[Key("rulesHash")] public string RulesHash { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets Verse ids this Verse can transfer from or subscribe to.
|
|
/// </summary>
|
|
[Key("compatibleVerseIds")] public string[] CompatibleVerseIds { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets required plugin ids.
|
|
/// </summary>
|
|
[Key("requiredPluginIds")] public string[] RequiredPluginIds { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets optional plugin ids.
|
|
/// </summary>
|
|
[Key("optionalPluginIds")] public string[] OptionalPluginIds { get; set; } = Array.Empty<string>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Requests known peers for a CultMesh Verse.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshPeerExchangeRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.PeerExchangeRequest;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the Verse id to discover peers for.
|
|
/// </summary>
|
|
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets optional role filters.
|
|
/// </summary>
|
|
[Key("roles")] public string[]? Roles { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets peer ids the requester already knows.
|
|
/// </summary>
|
|
[Key("knownPeerIds")] public string[]? KnownPeerIds { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the maximum number of peer cards to return.
|
|
/// </summary>
|
|
[Key("limit")] public int? Limit { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns known peers for a CultMesh Verse.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshPeerExchangeResponseMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.PeerExchangeResponse;
|
|
/// <summary>
|
|
/// Gets or sets the request id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets peer cards.
|
|
/// </summary>
|
|
[Key("peers")] public CultMeshPeerCardMessage[] Peers { get; set; } = Array.Empty<CultMeshPeerCardMessage>();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Requests one bounded content-addressed chunk over a managed CultMesh content session.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshContentChunkRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>Gets or sets the wire schema identity.</summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ContentChunkRequest;
|
|
/// <summary>Gets or sets the request correlation identity.</summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the canonical SHA-256 chunk identity.</summary>
|
|
[Key("chunkHash")] public string ChunkHash { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the optional canonical CultCache record key.</summary>
|
|
[Key("recordKey")] public string RecordKey { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the manifest-bound expected payload size.</summary>
|
|
[Key("expectedSizeBytes")] public int ExpectedSizeBytes { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Returns one bounded content-addressed chunk without publishing it as snapshot state.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshContentChunkResponseMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>Gets or sets the wire schema identity.</summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.ContentChunkResponse;
|
|
/// <summary>Gets or sets the matching request correlation identity.</summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets whether a validated chunk is present.</summary>
|
|
[Key("found")] public bool Found { get; set; }
|
|
/// <summary>Gets or sets the canonical SHA-256 chunk identity.</summary>
|
|
[Key("chunkHash")] public string ChunkHash { get; set; } = string.Empty;
|
|
/// <summary>Gets or sets the payload byte count.</summary>
|
|
[Key("sizeBytes")] public int SizeBytes { get; set; }
|
|
/// <summary>Gets or sets the bounded content payload.</summary>
|
|
[Key("payload")] public byte[] Payload { get; set; } = Array.Empty<byte>();
|
|
/// <summary>Gets or sets a typed-boundary failure description when the chunk is unavailable.</summary>
|
|
[Key("error")] public string Error { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Requests one immutable body generation from its capability owner. Body bytes travel on this
|
|
/// dedicated plane; they are never database snapshot records.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshBodyReadRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.BodyReadRequest;
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
[Key("capabilityToken")] public string CapabilityToken { get; set; } = string.Empty;
|
|
[Key("bodyId")] public string BodyId { get; set; } = string.Empty;
|
|
[Key("bodySchemaId")] public string BodySchemaId { get; set; } = string.Empty;
|
|
[Key("layoutVersion")] public int LayoutVersion { get; set; }
|
|
[Key("producerEpoch")] public long ProducerEpoch { get; set; }
|
|
[Key("sequence")] public long Sequence { get; set; }
|
|
[Key("expectedSizeBytes")] public long ExpectedSizeBytes { get; set; }
|
|
[Key("semanticHash")] public string SemanticHash { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>Returns one bounded immutable body generation directly to its subscriber.</summary>
|
|
[MessagePackObject]
|
|
public class CultMeshBodyReadResponseMessage : ICultNetSchemaMessage
|
|
{
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.BodyReadResponse;
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
[Key("found")] public bool Found { get; set; }
|
|
[Key("capabilityToken")] public string CapabilityToken { get; set; } = string.Empty;
|
|
[Key("bodyId")] public string BodyId { get; set; } = string.Empty;
|
|
[Key("producerEpoch")] public long ProducerEpoch { get; set; }
|
|
[Key("sequence")] public long Sequence { get; set; }
|
|
[Key("sizeBytes")] public long SizeBytes { get; set; }
|
|
[Key("semanticHash")] public string SemanticHash { get; set; } = string.Empty;
|
|
[Key("payload")] public byte[] Payload { get; set; } = Array.Empty<byte>();
|
|
[Key("error")] public string Error { get; set; } = string.Empty;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Wire representation of a CultMesh peer candidate.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultMeshPeerCardMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the stable peer id.
|
|
/// </summary>
|
|
[Key("peerId")] public string PeerId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the Verse id this peer participates in.
|
|
/// </summary>
|
|
[Key("verseId")] public string VerseId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets reachable endpoints.
|
|
/// </summary>
|
|
[Key("endpoints")] public string[] Endpoints { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets advertised peer roles.
|
|
/// </summary>
|
|
[Key("roles")] public string[] Roles { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets shard ids this peer can serve or observe.
|
|
/// </summary>
|
|
[Key("shardIds")] public string[] ShardIds { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets an optional region/locality label.
|
|
/// </summary>
|
|
[Key("region")] public string? Region { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the authority lease id, when the card advertises authority.
|
|
/// </summary>
|
|
[Key("authorityLeaseId")] public string? AuthorityLeaseId { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the expiry timestamp for this card.
|
|
/// </summary>
|
|
[Key("expiresAt")] public string? ExpiresAt { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets an optional signature over the card.
|
|
/// </summary>
|
|
[Key("signature")] public string? Signature { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// Describes one schema exposed through the CultNet schema catalog.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSchemaDescriptor
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema id.
|
|
/// </summary>
|
|
[Key("schemaId")] public string SchemaId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the kind.
|
|
/// </summary>
|
|
[Key("kind")] public string Kind { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string? SchemaVersion { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the document type.
|
|
/// </summary>
|
|
[Key("documentType")] public string? DocumentType { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the title.
|
|
/// </summary>
|
|
[Key("title")] public string? Title { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the wire contracts.
|
|
/// </summary>
|
|
[Key("wireContracts")] public string[] WireContracts { get; set; } = Array.Empty<string>();
|
|
/// <summary>
|
|
/// Gets or sets the content hash.
|
|
/// </summary>
|
|
[Key("contentHash")] public string ContentHash { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the schema json.
|
|
/// </summary>
|
|
[Key("schemaJson")] public string? SchemaJson { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message requesting schema catalog entries.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSchemaCatalogRequestMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SchemaCatalogRequest;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the include schema json.
|
|
/// </summary>
|
|
[Key("includeSchemaJson")] public bool IncludeSchemaJson { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the schema ids.
|
|
/// </summary>
|
|
[Key("schemaIds")] public string[]? SchemaIds { get; set; }
|
|
/// <summary>
|
|
/// Gets or sets the kinds.
|
|
/// </summary>
|
|
[Key("kinds")] public string[]? Kinds { get; set; }
|
|
}
|
|
|
|
/// <summary>
|
|
/// CultNet message returning schema catalog entries.
|
|
/// </summary>
|
|
[MessagePackObject]
|
|
public class CultNetSchemaCatalogResponseMessage : ICultNetSchemaMessage
|
|
{
|
|
/// <summary>
|
|
/// Gets or sets the schema version.
|
|
/// </summary>
|
|
[Key("schemaVersion")] public string SchemaVersion { get; set; } = CultNetSchemaVersions.SchemaCatalogResponse;
|
|
/// <summary>
|
|
/// Gets or sets the message id.
|
|
/// </summary>
|
|
[Key("messageId")] public string MessageId { get; set; } = string.Empty;
|
|
/// <summary>
|
|
/// Gets or sets the schemas.
|
|
/// </summary>
|
|
[Key("schemas")] public CultNetSchemaDescriptor[] Schemas { get; set; } = Array.Empty<CultNetSchemaDescriptor>();
|
|
}
|
|
}
|