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