void RegisterRoutingModule( ContainerBuilder builder, StoreAndForward storeAndForward, ExperimentalFeatures experimentalFeatures, bool nestedEdgeEnabled, bool scopeAuthenticationOnly, bool trackDeviceState) { var routes = this.configuration.GetSection("routes").Get <Dictionary <string, string> >(); int connectionPoolSize = this.configuration.GetValue <int>("IotHubConnectionPoolSize"); string configSource = this.configuration.GetValue <string>("configSource"); bool useTwinConfig = !string.IsNullOrWhiteSpace(configSource) && configSource.Equals("twin", StringComparison.OrdinalIgnoreCase); Option <UpstreamProtocol> upstreamProtocolOption = GetUpstreamProtocol(this.configuration); int connectivityCheckFrequencySecs = this.configuration.GetValue("ConnectivityCheckFrequencySecs", 300); TimeSpan connectivityCheckFrequency = connectivityCheckFrequencySecs < 0 ? TimeSpan.MaxValue : TimeSpan.FromSeconds(connectivityCheckFrequencySecs); // n Clients + 1 Edgehub int maxConnectedClients = this.configuration.GetValue("MaxConnectedClients", 100) + 1; int messageAckTimeoutSecs = this.configuration.GetValue("MessageAckTimeoutSecs", 30); TimeSpan messageAckTimeout = TimeSpan.FromSeconds(messageAckTimeoutSecs); int cloudConnectionIdleTimeoutSecs = this.configuration.GetValue("CloudConnectionIdleTimeoutSecs", 3600); TimeSpan cloudConnectionIdleTimeout = TimeSpan.FromSeconds(cloudConnectionIdleTimeoutSecs); bool closeCloudConnectionOnIdleTimeout = this.configuration.GetValue("CloseCloudConnectionOnIdleTimeout", true); int cloudOperationTimeoutSecs = this.configuration.GetValue("CloudOperationTimeoutSecs", 20); bool useServerHeartbeat = this.configuration.GetValue("UseServerHeartbeat", true); TimeSpan cloudOperationTimeout = TimeSpan.FromSeconds(cloudOperationTimeoutSecs); Option <TimeSpan> minTwinSyncPeriod = this.GetConfigurationValueIfExists("MinTwinSyncPeriodSecs") .Map(s => TimeSpan.FromSeconds(s)); Option <TimeSpan> reportedPropertiesSyncFrequency = this.GetConfigurationValueIfExists("ReportedPropertiesSyncFrequencySecs") .Map(s => TimeSpan.FromSeconds(s)); bool useV1TwinManager = this.GetConfigurationValueIfExists <string>("TwinManagerVersion") .Map(v => v.Equals("v1", StringComparison.OrdinalIgnoreCase)) .GetOrElse(false); int maxUpstreamBatchSize = this.configuration.GetValue("MaxUpstreamBatchSize", 10); int upstreamFanOutFactor = this.configuration.GetValue("UpstreamFanOutFactor", 10); bool encryptTwinStore = this.configuration.GetValue("EncryptTwinStore", true); int configUpdateFrequencySecs = this.configuration.GetValue("ConfigRefreshFrequencySecs", 3600); TimeSpan configUpdateFrequency = TimeSpan.FromSeconds(configUpdateFrequencySecs); bool checkEntireQueueOnCleanup = this.configuration.GetValue("CheckEntireQueueOnCleanup", false); int messageCleanupIntervalSecs = this.configuration.GetValue("MessageCleanupIntervalSecs", 1800); bool closeCloudConnectionOnDeviceDisconnect = this.configuration.GetValue("CloseCloudConnectionOnDeviceDisconnect", true); bool isLegacyUpstream = ExperimentalFeatures.IsViaBrokerUpstream( experimentalFeatures, nestedEdgeEnabled, this.GetConfigurationValueIfExists <string>(Constants.ConfigKey.GatewayHostname).HasValue); builder.RegisterModule( new RoutingModule( this.iotHubHostname, this.gatewayHostname, this.edgeDeviceId, this.edgeModuleId, this.connectionString, routes, storeAndForward.IsEnabled, storeAndForward.Config, connectionPoolSize, useTwinConfig, this.versionInfo, upstreamProtocolOption, connectivityCheckFrequency, maxConnectedClients, messageAckTimeout, cloudConnectionIdleTimeout, closeCloudConnectionOnIdleTimeout, cloudOperationTimeout, useServerHeartbeat, minTwinSyncPeriod, reportedPropertiesSyncFrequency, useV1TwinManager, maxUpstreamBatchSize, upstreamFanOutFactor, encryptTwinStore, configUpdateFrequency, checkEntireQueueOnCleanup, messageCleanupIntervalSecs, experimentalFeatures, closeCloudConnectionOnDeviceDisconnect, nestedEdgeEnabled, isLegacyUpstream, scopeAuthenticationOnly: scopeAuthenticationOnly, trackDeviceState: trackDeviceState)); }
static async Task <int> MainAsync(IConfigurationRoot configuration) { string logLevel = configuration.GetValue($"{Logger.RuntimeLogLevelEnvKey}", "info"); Logger.SetLogLevel(logLevel); // Set the LoggerFactory used by the Routing code. if (configuration.GetValue("EnableRoutingLogging", false)) { Routing.LoggerFactory = Logger.Factory; } ILogger logger = Logger.Factory.CreateLogger("EdgeHub"); EdgeHubCertificates certificates = await EdgeHubCertificates.LoadAsync(configuration, logger); bool clientCertAuthEnabled = configuration.GetValue(Constants.ConfigKey.EdgeHubClientCertAuthEnabled, false); string sslProtocolsConfig = configuration.GetValue(Constants.ConfigKey.SslProtocols, string.Empty); SslProtocols sslProtocols = SslProtocolsHelper.Parse(sslProtocolsConfig, DefaultSslProtocols, logger); logger.LogInformation($"Enabling SSL protocols: {sslProtocols.Print()}"); IDependencyManager dependencyManager = new DependencyManager(configuration, certificates.ServerCertificate, certificates.TrustBundle, sslProtocols); Hosting hosting = Hosting.Initialize(configuration, certificates.ServerCertificate, dependencyManager, clientCertAuthEnabled, sslProtocols); IContainer container = hosting.Container; logger.LogInformation("Initializing Edge Hub"); LogLogo(logger); LogVersionInfo(logger); logger.LogInformation($"OptimizeForPerformance={configuration.GetValue("OptimizeForPerformance", true)}"); logger.LogInformation($"MessageAckTimeoutSecs={configuration.GetValue("MessageAckTimeoutSecs", 30)}"); logger.LogInformation("Loaded server certificate with expiration date of {0}", certificates.ServerCertificate.NotAfter.ToString("o")); var metricsProvider = container.Resolve <IMetricsProvider>(); Metrics.InitWithAspNet(metricsProvider, logger); // Note this requires App.UseMetricServer() to be called in Startup.cs // EdgeHub and CloudConnectionProvider have a circular dependency. So need to Bind the EdgeHub to the CloudConnectionProvider. IEdgeHub edgeHub = await container.Resolve <Task <IEdgeHub> >(); ICloudConnectionProvider cloudConnectionProvider = await container.Resolve <Task <ICloudConnectionProvider> >(); cloudConnectionProvider.BindEdgeHub(edgeHub); // EdgeHub cloud proxy and DeviceConnectivityManager have a circular dependency, // so the cloud proxy has to be set on the DeviceConnectivityManager after both have been initialized. var deviceConnectivityManager = container.Resolve <IDeviceConnectivityManager>(); IConnectionManager connectionManager = await container.Resolve <Task <IConnectionManager> >(); (deviceConnectivityManager as DeviceConnectivityManager)?.SetConnectionManager(connectionManager); // Register EdgeHub credentials var edgeHubCredentials = container.ResolveNamed <IClientCredentials>("EdgeHubCredentials"); ICredentialsCache credentialsCache = await container.Resolve <Task <ICredentialsCache> >(); await credentialsCache.Add(edgeHubCredentials); // Initializing configuration logger.LogInformation("Initializing configuration"); IConfigSource configSource = await container.Resolve <Task <IConfigSource> >(); ConfigUpdater configUpdater = await container.Resolve <Task <ConfigUpdater> >(); ExperimentalFeatures experimentalFeatures = CreateExperimentalFeatures(configuration); var configUpdaterStartupFailed = new TaskCompletionSource <bool>(); var configDownloadTask = configUpdater.Init(configSource); _ = configDownloadTask.ContinueWith( _ => configUpdaterStartupFailed.SetResult(false), TaskContinuationOptions.OnlyOnFaulted); if (!ExperimentalFeatures.IsViaBrokerUpstream( experimentalFeatures, string.IsNullOrEmpty(configuration.GetValue <string>(Constants.ConfigKey.GatewayHostname)))) { await configDownloadTask; } if (!Enum.TryParse(configuration.GetValue("AuthenticationMode", string.Empty), true, out AuthenticationMode authenticationMode) || authenticationMode != AuthenticationMode.Cloud) { ConnectionReauthenticator connectionReauthenticator = await container.Resolve <Task <ConnectionReauthenticator> >(); connectionReauthenticator.Init(); } TimeSpan shutdownWaitPeriod = TimeSpan.FromSeconds(configuration.GetValue("ShutdownWaitPeriod", DefaultShutdownWaitPeriod)); (CancellationTokenSource cts, ManualResetEventSlim completed, Option <object> handler) = ShutdownHandler.Init(shutdownWaitPeriod, logger); using (IProtocolHead protocolHead = await GetEdgeHubProtocolHeadAsync(logger, configuration, experimentalFeatures, container, hosting)) using (var renewal = new CertificateRenewal(certificates, logger)) { try { await protocolHead.StartAsync(); await Task.WhenAny(cts.Token.WhenCanceled(), renewal.Token.WhenCanceled(), configUpdaterStartupFailed.Task); } catch (Exception ex) { logger.LogError($"Error starting protocol heads: {ex.Message}"); } logger.LogInformation("Stopping the protocol heads..."); await protocolHead.CloseAsync(CancellationToken.None); logger.LogInformation("Protocol heads stopped."); await CloseDbStoreProviderAsync(container); } completed.Set(); handler.ForEach(h => GC.KeepAlive(h)); logger.LogInformation("Shutdown complete."); return(0); }