using System; using System.Linq; using System.Threading.Tasks; using GameCult.Caching; using GameCult.Caching.MessagePack; namespace GameCult.Networking { /// /// Options for creating a local CultNet host over CultCache and the canonical MessagePack store. /// public sealed class CultNetHostOptions { /// /// Gets or sets the cache-open options used for the underlying CultCache. /// public CultCacheOpenOptions? CacheOptions { get; set; } /// /// Gets or sets the server security configuration. When omitted, development defaults are used. /// public ServerSecurityOptions? Security { get; set; } /// /// Gets or sets whether the server should start immediately after creation. /// public bool StartServer { get; set; } = true; /// /// Gets or sets the database sharding options used for the hosted CultCache. /// public CultNetDatabaseOptions? DatabaseOptions { get; set; } /// /// Gets or sets the database server bridge options used for shard routing and forwarding. /// public CultNetDatabaseServerOptions? DatabaseServerOptions { get; set; } /// /// Gets or sets an optional callback used to customize the server before start. /// public Action? ConfigureServer { get; set; } } /// /// Convenience wrapper for a locally hosted CultNet server over a durable CultCache. /// public sealed class CultNetHost : IDisposable { internal CultNetHost( CultCache cache, SingleFileMessagePackBackingStore? store, Server server, CultNetDatabase database, CultNetDatabaseServer databaseServer) { Cache = cache; Store = store; Server = server; Database = database; DatabaseServer = databaseServer; } /// /// Gets the durable cache used by the host. /// public CultCache Cache { get; } /// /// Gets the canonical single-file MessagePack store, when one is attached. /// public SingleFileMessagePackBackingStore? Store { get; } /// /// Gets the underlying CultNet server. /// public Server Server { get; } /// /// Gets the distributed database facade over the hosted cache. /// public CultNetDatabase Database { get; } /// /// Gets the schema-v0 server bridge for distributed database messages. /// public CultNetDatabaseServer DatabaseServer { get; } /// /// Starts the server. /// public void Start() { Server.Start(); } /// /// Flushes the durable cache. /// public Task FlushAsync(bool soft = false) { return Cache.FlushAsync(soft); } /// /// Stops the server and disposes the host resources. /// public void Dispose() { DatabaseServer.Dispose(); Server.Dispose(); Database.Dispose(); Cache.Dispose(); } } /// /// Friendly local entrypoints for CultNet host/client creation. /// public static class CultNetLocal { /// /// Creates a local host with a durable CultCache and the canonical MessagePack backing store. /// public static async Task CreateHostAsync(string cachePath, CultNetHostOptions? options = null) { if (string.IsNullOrWhiteSpace(cachePath)) { throw new ArgumentException("Cache path must be non-empty.", nameof(cachePath)); } options ??= new CultNetHostOptions(); var cache = await CultCacheMessagePack.OpenAsync(cachePath, options.CacheOptions).ConfigureAwait(false); var store = cache.BackingStores.OfType().FirstOrDefault(); var server = new Server(cache, options.Security ?? ServerSecurityOptions.Development()); var databaseOptions = options.DatabaseOptions ?? new CultNetDatabaseOptions(); var database = new CultNetDatabase(cache, databaseOptions); var databaseServer = new CultNetDatabaseServer(server, database, options.DatabaseServerOptions); options.ConfigureServer?.Invoke(server); var host = new CultNetHost(cache, store, server, database, databaseServer); if (options.StartServer) { host.Start(); } return host; } /// /// Creates and starts a local host with development-friendly defaults. /// public static Task StartHostAsync(string cachePath, CultNetHostOptions? options = null) { options ??= new CultNetHostOptions(); options.StartServer = true; return CreateHostAsync(cachePath, options); } /// /// Creates a client configured for local CultNet use. /// public static Client CreateClient(ClientSecurityOptions? security = null, Action? configureClient = null) { var client = new Client(security ?? ClientSecurityOptions.Development()); configureClient?.Invoke(client); return client; } /// /// Creates and connects a client to the specified host. /// public static Client ConnectClient( string host = "localhost", int port = 3075, ClientSecurityOptions? security = null, Action? configureClient = null) { var client = CreateClient(security, configureClient); client.Connect(host, port); return client; } /// /// Creates and connects a client to a local development host. /// public static Client ConnectLocal( ClientSecurityOptions? security = null, Action? configureClient = null) { return ConnectClient("localhost", 3075, security, configureClient); } } }