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);
}
}
}