using System.Net; using System.Linq; using System.Net.Sockets; using EventStore.ClientAPI.Common.Utils; using EventStore.ClientAPI.Internal; using System; using EventStore.ClientAPI.SystemData; namespace EventStore.ClientAPI { /// /// Contains factory methods for building connections to an Event Store server. /// public static class EventStoreConnection { /// /// Creates a new to single node using default /// /// Optional name of connection (will be generated automatically, if not provided) /// The Uri to connect to. It can be tcp:// to point to a single node or discover:// to discover nodes /// a new public static IEventStoreConnection Create(Uri uri, string connectionName = null) { return Create(ConnectionSettings.Default, uri, connectionName); } /// /// Creates a new to single node using default provided via a connectionstring /// /// Optional name of connection (will be generated automatically, if not provided) /// The connection string to for this connection. /// a new public static IEventStoreConnection Create(string connectionString, string connectionName = null) { return Create(connectionString, null, connectionName); } /// /// Creates a new to single node using default provided via a connectionstring /// /// Optional name of connection (will be generated automatically, if not provided) /// Pre-populated settings builder, optional. If not specified, a new builder will be created. /// The connection string to for this connection. /// a new public static IEventStoreConnection Create(string connectionString, ConnectionSettingsBuilder builder, string connectionName = null) { var settings = ConnectionString.GetConnectionSettings(connectionString, builder); var uri = GetUriFromConnectionString(connectionString); if (uri == null && (settings.GossipSeeds == null || settings.GossipSeeds.Length == 0)) { throw new Exception(string.Format("Did not find ConnectTo or GossipSeeds in the connection string.\n'{0}'", connectionString)); } if (uri != null && settings.GossipSeeds != null && settings.GossipSeeds.Length > 0) { throw new NotSupportedException(string.Format("Setting ConnectTo as well as GossipSeeds on the connection string is currently not supported.\n{0}", connectionString)); } return Create(settings, uri, connectionName); } /// /// Creates a new using the gossip seeds specified in the /// /// Optional name of connection (will be generated automatically, if not provided) /// The to apply to the new connection /// a new public static IEventStoreConnection Create(ConnectionSettings connectionSettings, string connectionName = null) { if (connectionSettings.GossipSeeds == null || connectionSettings.GossipSeeds.Length == 0) throw new ArgumentException("No gossip seeds specified", nameof(connectionSettings)); return Create(connectionSettings, (Uri)null, connectionName); } /// /// Creates a new /// /// Optional name of connection (will be generated automatically, if not provided) /// The to apply to the new connection. If null the default settings will be used and the must not be null /// The Uri to connect to. It can be tcp:// to point to a single node or discover:// to discover nodes via dns or null to connect using the gossip seeds from the /// a new /// You must pass a uri or set gossip seeds in the connection settings. public static IEventStoreConnection Create(ConnectionSettings connectionSettings, Uri uri, string connectionName = null) { connectionSettings = connectionSettings ?? ConnectionSettings.Default; if (uri != null) { var scheme = uri.Scheme.ToLower(); var credential = GetCredentialFromUri(uri); if (credential != null) { connectionSettings = new ConnectionSettings(connectionSettings.Log, connectionSettings.VerboseLogging, connectionSettings.MaxQueueSize, connectionSettings.MaxConcurrentItems, connectionSettings.MaxRetries, connectionSettings.MaxReconnections, connectionSettings.RequireMaster, connectionSettings.ReconnectionDelay, connectionSettings.QueueTimeout, connectionSettings.OperationTimeout, connectionSettings.OperationTimeoutCheckPeriod, credential, connectionSettings.UseSslConnection, connectionSettings.TargetHost, connectionSettings.ValidateServer, connectionSettings.FailOnNoServerResponse, connectionSettings.HeartbeatInterval, connectionSettings.HeartbeatTimeout, connectionSettings.ClientConnectionTimeout, connectionSettings.ClusterDns, connectionSettings.GossipSeeds, connectionSettings.MaxDiscoverAttempts, connectionSettings.ExternalGossipPort, connectionSettings.GossipTimeout, connectionSettings.NodePreference); } if (scheme == "discover") { var clusterSettings = new ClusterSettings(uri.Host, connectionSettings.MaxDiscoverAttempts, uri.Port, connectionSettings.GossipTimeout, connectionSettings.NodePreference); Ensure.NotNull(connectionSettings, "connectionSettings"); Ensure.NotNull(clusterSettings, "clusterSettings"); var endPointDiscoverer = new ClusterDnsEndPointDiscoverer(connectionSettings.Log, clusterSettings.ClusterDns, clusterSettings.MaxDiscoverAttempts, clusterSettings.ExternalGossipPort, clusterSettings.GossipSeeds, clusterSettings.GossipTimeout, clusterSettings.NodePreference); return new EventStoreNodeConnection(connectionSettings, clusterSettings, endPointDiscoverer, connectionName); } if (scheme == "tcp") { return new EventStoreNodeConnection(connectionSettings, null, new SingleEndpointDiscoverer(uri, connectionSettings.UseSslConnection), connectionName); } throw new Exception(string.Format("Unknown scheme for connection '{0}'", scheme)); } if (connectionSettings.GossipSeeds != null && connectionSettings.GossipSeeds.Length > 0) { var clusterSettings = new ClusterSettings(connectionSettings.GossipSeeds, connectionSettings.MaxDiscoverAttempts, connectionSettings.GossipTimeout, connectionSettings.NodePreference); Ensure.NotNull(connectionSettings, "connectionSettings"); Ensure.NotNull(clusterSettings, "clusterSettings"); var endPointDiscoverer = new ClusterDnsEndPointDiscoverer(connectionSettings.Log, clusterSettings.ClusterDns, clusterSettings.MaxDiscoverAttempts, clusterSettings.ExternalGossipPort, clusterSettings.GossipSeeds, clusterSettings.GossipTimeout, clusterSettings.NodePreference); return new EventStoreNodeConnection(connectionSettings, clusterSettings, endPointDiscoverer, connectionName); } throw new Exception($"Must specify uri or gossip seeds"); } private static UserCredentials GetCredentialFromUri(Uri uri) { if (uri == null || string.IsNullOrEmpty(uri.UserInfo)) return null; var pieces = uri.UserInfo.Split(':'); if (pieces.Length != 2) throw new Exception(string.Format("Unable to parse user information '{0}'", uri.UserInfo)); return new UserCredentials(pieces[0], pieces[1]); } private static Uri GetUriFromConnectionString(string connectionString) { var connto = ConnectionString.GetConnectionStringInfo(connectionString) .FirstOrDefault(x => x.Key.ToUpperInvariant() == "CONNECTTO").Value; return connto == null ? null : new Uri(connto); } /// /// Creates a new to single node using default /// /// Optional name of connection (will be generated automatically, if not provided) /// The to connect to. /// a new public static IEventStoreConnection Create(IPEndPoint tcpEndPoint, string connectionName = null) { return Create(ConnectionSettings.Default, tcpEndPoint, connectionName); } /// /// Creates a new to single node using specific /// /// The to apply to the new connection /// The to connect to. /// Optional name of connection (will be generated automatically, if not provided) /// a new public static IEventStoreConnection Create(ConnectionSettings connectionSettings, IPEndPoint tcpEndPoint, string connectionName = null) { Ensure.NotNull(connectionSettings, "settings"); Ensure.NotNull(tcpEndPoint, "tcpEndPoint"); return new EventStoreNodeConnection(connectionSettings, null, new StaticEndPointDiscoverer(tcpEndPoint, connectionSettings.UseSslConnection), connectionName); } /// /// Creates a new to EventStore cluster /// using specific and /// /// The to apply to the new connection /// The that determine cluster behavior. /// Optional name of connection (will be generated automatically, if not provided) /// a new public static IEventStoreConnection Create(ConnectionSettings connectionSettings, ClusterSettings clusterSettings, string connectionName = null) { Ensure.NotNull(connectionSettings, "connectionSettings"); Ensure.NotNull(clusterSettings, "clusterSettings"); var endPointDiscoverer = new ClusterDnsEndPointDiscoverer(connectionSettings.Log, clusterSettings.ClusterDns, clusterSettings.MaxDiscoverAttempts, clusterSettings.ExternalGossipPort, clusterSettings.GossipSeeds, clusterSettings.GossipTimeout, clusterSettings.NodePreference); return new EventStoreNodeConnection(connectionSettings, clusterSettings, endPointDiscoverer, connectionName); } /// /// Creates a new using specific and a custom-defined /// /// The to apply to the new connection /// The custom-defined to use for node discovery /// Optional name of connection (will be generated automatically, if not provided) /// a new public static IEventStoreConnection Create(ConnectionSettings connectionSettings, IEndPointDiscoverer endPointDiscoverer, string connectionName = null) { Ensure.NotNull(connectionSettings, "settings"); Ensure.NotNull(endPointDiscoverer, "endPointDiscoverer"); return new EventStoreNodeConnection(connectionSettings, null, endPointDiscoverer, connectionName); } } }