From 22bb9afaa4b2261fa05317f1a4b7743e2e96cb04 Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 18 Aug 2026 06:23:26 +0200 Subject: [PATCH] Use one CultMesh node in Eve onboarding --- samples/eve-browser-network/Program.cs | 47 ++++++++++--------- samples/eve-browser-network/README.md | 3 +- .../getting-started/01-persist-typed-state.md | 35 +++++++------- 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/samples/eve-browser-network/Program.cs b/samples/eve-browser-network/Program.cs index 82c09c19..fe6a74b9 100644 --- a/samples/eve-browser-network/Program.cs +++ b/samples/eve-browser-network/Program.cs @@ -72,29 +72,32 @@ static async Task RunOdinAsync(Args arguments) static async Task RunProviderAsync(Args arguments) { - var registry = CultDocumentRegistry.ForTypes([typeof(CounterState), typeof(EveSurfaceDocument)]); - using var cache = await CultCacheMessagePack.OpenAsync(arguments.StatePath, new CultCacheOpenOptions + var documentTypes = new[] { typeof(CounterState), typeof(EveSurfaceDocument) }; + var registry = CultMesh.CreateCultCacheDocumentRegistry(documentTypes); + var documents = CultMesh.CreateCultNetDocumentRegistry(documentTypes, registry); + using var node = await CultMesh.CreateNodeAsync(arguments.StatePath, new CultMeshNodeOptions { - Registry = registry, - FlushOnDispose = true, - StoreFlushOnDispose = true + StartServer = false, + CacheOptions = new CultCacheOpenOptions + { + Registry = registry, + FlushOnDispose = true, + StoreFlushOnDispose = true + }, + DatabaseOptions = new CultNetDatabaseOptions + { + RuntimeId = "sample.counter-provider", + DocumentRegistry = documents + } }); - var documents = new CultNetDocumentRegistry(registry) - .Register(CultNetDocumentBinding.ForDocument(registry, "sample.counter_state.v1")) - .Register(CultNetDocumentBinding.ForDocument(registry, EveSurfaceDocument.SchemaId)); - using var database = new CultNetDatabase(cache, new CultNetDatabaseOptions - { - RuntimeId = "sample.counter-provider", - DocumentRegistry = documents - }); - if (cache.Get(new CultRecordKey(counterKey)) == null) - await database.PutAsync(new CultRecordKey(counterKey), CounterState.Initial(counterKey)); - if (cache.Get(new CultRecordKey(surfaceKey)) == null) - await database.PutAsync(new CultRecordKey(surfaceKey), CreateCounterSurface()); - await cache.FlushAsync(); + if (node.Cache.Get(new CultRecordKey(counterKey)) == null) + await node.Database.PutAsync(new CultRecordKey(counterKey), CounterState.Initial(counterKey)); + if (node.Cache.Get(new CultRecordKey(surfaceKey)) == null) + await node.Database.PutAsync(new CultRecordKey(surfaceKey), CreateCounterSurface()); + await node.FlushAsync(); await using var schemaServer = new CultNetWebSocketSchemaServer(); - using var subscriptions = new CultNetDatabaseSubscriptionServer(schemaServer, database); + using var subscriptions = new CultNetDatabaseSubscriptionServer(schemaServer, node.Database); using var operationGate = new SemaphoreSlim(1, 1); using var operations = new CultNetOperationServer(schemaServer, "sample.counter-provider") .Register( @@ -113,7 +116,7 @@ static async Task RunProviderAsync(Args arguments) await operationGate.WaitAsync(); try { - var current = cache.Get(new CultRecordKey(counterKey)) + var current = node.Cache.Get(new CultRecordKey(counterKey)) ?? throw new InvalidOperationException("Counter state is unavailable."); if (current.Receipts.TryGetValue(context.IdempotencyKey, out var existing)) return existing; @@ -125,13 +128,13 @@ static async Task RunProviderAsync(Args arguments) { [context.IdempotencyKey] = receipt }; - await database.PutAsync(new CultRecordKey(counterKey), new CounterState + await node.Database.PutAsync(new CultRecordKey(counterKey), new CounterState { CounterId = counterKey, Count = receipt.Count, Receipts = receipts }); - await cache.FlushAsync(); + await node.FlushAsync(); return receipt; } finally diff --git a/samples/eve-browser-network/README.md b/samples/eve-browser-network/README.md index bbcc95ca..7ad20a00 100644 --- a/samples/eve-browser-network/README.md +++ b/samples/eve-browser-network/README.md @@ -19,7 +19,8 @@ The provider registers typed commands through `CultNetOperationServer`. Application code receives `CultNetOperationContext` and returns a typed receipt; it does not parse base64, switch on wire envelopes, or construct correlation responses. The counter's durable transaction still owns -idempotency and state mutation. +idempotency and state mutation. The provider opens one public `CultMeshNode`; +it does not assemble a parallel CultCache/CultNet database host by hand. Run the proof from the CultLib repository: diff --git a/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md b/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md index 6e2d2b3b..c2667e9b 100644 --- a/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md +++ b/src/GameCult.Mesh/docs/getting-started/01-persist-typed-state.md @@ -7,6 +7,7 @@ client. Start with the state the provider actually owns. ```csharp using GameCult.Caching; using GameCult.Caching.MessagePack; +using GameCult.Mesh; using GameCult.Networking; using MessagePack; @@ -19,35 +20,31 @@ public sealed class CounterState } ``` -Open a `.cc` store, register the document once, and write through the CultMesh -database boundary: +Open a `.cc` node, register the document once, and write through its database +boundary: ```csharp var key = new CultRecordKey("counter:main"); -var registry = CultDocumentRegistry.ForTypes([typeof(CounterState)]); - -using var cache = await CultCacheMessagePack.OpenAsync("counter.cc", new CultCacheOpenOptions +var documentTypes = new[] { typeof(CounterState) }; +var registry = CultMesh.CreateCultCacheDocumentRegistry(documentTypes); +var documents = CultMesh.CreateCultNetDocumentRegistry(documentTypes, registry); +using var node = await CultMesh.CreateNodeAsync("counter.cc", new CultMeshNodeOptions { - Registry = registry, - FlushOnDispose = true, - StoreFlushOnDispose = true -}); -var documents = new CultNetDocumentRegistry(registry) - .Register(CultNetDocumentBinding.ForDocument( - registry, - "sample.counter_state.v1")); -using var database = new CultNetDatabase(cache, new CultNetDatabaseOptions -{ - RuntimeId = "sample.counter-provider", - DocumentRegistry = documents + StartServer = false, + CacheOptions = new CultCacheOpenOptions { Registry = registry }, + DatabaseOptions = new CultNetDatabaseOptions + { + RuntimeId = "sample.counter-provider", + DocumentRegistry = documents + } }); -await database.PutAsync(key, new CounterState +await node.Database.PutAsync(key, new CounterState { CounterId = key.Value, Count = 0 }); -await cache.FlushAsync(); +await node.FlushAsync(); ``` CultCache owns durable local truth. CultNet owns the portable schema mapping.