/* * Copyright (c) 2024 Vaughn Nugent * * Library: VNLib * Package: ObjectCacheServer * File: ServerClusterConfig.cs * * ServerClusterConfig.cs is part of ObjectCacheServer which is part of the larger * VNLib collection of libraries and utilities. * * ObjectCacheServer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * ObjectCacheServer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see https://www.gnu.org/licenses/. */ using System; using System.Net; using System.Linq; using System.Text.Json; using System.Collections.Generic; using VNLib.Plugins; using VNLib.Utils.Logging; using VNLib.Utils.Extensions; using VNLib.Plugins.Extensions.Loading; using VNLib.Data.Caching.Extensions.Clustering; namespace VNLib.Data.Caching.ObjectCache.Server { [ConfigurationName("cluster")] internal sealed class ServerClusterConfig(PluginBase plugin, IConfigScope config) { public TimeSpan DiscoveryInterval { get; } = config.GetRequiredProperty("discovery_interval_sec", p => p.GetTimeSpan(TimeParseType.Seconds)); public TimeSpan EventQueuePurgeInterval { get; } = config.GetRequiredProperty("queue_purge_interval_sec", p => p.GetTimeSpan(TimeParseType.Seconds)); public int MaxQueueDepth { get; } = (int)config.GetRequiredProperty("max_queue_depth", p => p.GetUInt32()); public string? DiscoveryPath { get; } = config.GetValueOrDefault("discovery_path", p => p.GetString(), null); public string ConnectPath { get; } = config.GetRequiredProperty("connect_path", p => p.GetString()!); public string WellKnownPath { get; } = config.GetValueOrDefault("well_known_path", p => p.GetString()!, CacheConstants.DefaultWellKnownPath) ?? CacheConstants.DefaultWellKnownPath; public bool VerifyIp { get; } = config.GetRequiredProperty("verify_ip", p => p.GetBoolean()); /// /// The maximum number of peer connections to allow /// public uint MaxPeerConnections { get; } = config.GetValueOrDefault("max_peers", p => p.GetUInt32(), 10u); /// /// The maxium number of concurrent client connections to allow /// before rejecting new connections /// public uint MaxConcurrentConnections { get; } = config.GetValueOrDefault("max_concurrent_connections", p => p.GetUInt32(), 100u); const string CacheConfigTemplate = @" Cluster Configuration: Node Id: {id} TlsEndabled: {tls} Verify Ip: {vi} Well-Known: {wk} Cache Endpoint: {ep} Discovery Endpoint: {dep} Discovery Interval: {di} Max Peer Connections: {mpc} Max Queue Depth: {mqd} Event Queue Purge Interval: {eqpi} "; internal CacheNodeConfiguration BuildNodeConfig() { CacheNodeConfiguration conf = new(); //Get the port of the primary webserver int port; bool usingTls; { //Get the port number of the first virtual host JsonElement firstHost = plugin.HostConfig.GetProperty("virtual_hosts") .EnumerateArray() .First(); port = firstHost.GetProperty("interface") .GetProperty("port") .GetInt32(); //If the ssl element is present, ssl is enabled for the server usingTls = firstHost.TryGetProperty("ssl", out _); } string hostname = Dns.GetHostName(); //Server id is just dns name for now string nodeId = $"{hostname}:{port}"; Uri connectEp = BuildUri(usingTls, hostname, port, ConnectPath); Uri? discoveryEp = null; conf.WithCacheEndpoint(connectEp) .WithNodeId(nodeId) .WithTls(usingTls); //Get the discovery path (optional) if (!string.IsNullOrWhiteSpace(DiscoveryPath)) { //Build the discovery endpoint, it must be an absolute uri discoveryEp = BuildUri(usingTls, hostname, port, DiscoveryPath); conf.EnableAdvertisment(discoveryEp); } //print the cluster configuration to the log plugin.Log.Information(CacheConfigTemplate, nodeId, usingTls, VerifyIp, WellKnownPath, connectEp, discoveryEp, DiscoveryInterval, MaxPeerConnections, MaxQueueDepth, EventQueuePurgeInterval ); return conf; } private static Uri BuildUri(bool tls, string host, int port, string path) { return new UriBuilder { Scheme = tls ? "https" : "http", Host = host, Port = port, Path = path }.Uri; } } }