using System; using System.Collections.Generic; using System.Threading; using System.Web; using Semver; using Umbraco.Core.Configuration; using Umbraco.Core.Configuration.UmbracoSettings; using Umbraco.Core.Exceptions; using Umbraco.Core.Logging; using Umbraco.Core.Sync; namespace Umbraco.Core { /// /// Represents the state of the Umbraco runtime. /// internal class RuntimeState : IRuntimeState { private readonly ILogger _logger; private readonly Lazy _serverRegistrar; private readonly Lazy _mainDom; private readonly IUmbracoSettingsSection _settings; private readonly IGlobalSettings _globalSettings; private readonly HashSet _applicationUrls = new HashSet(); private RuntimeLevel _level; /// /// Initializes a new instance of the class. /// /// A logger. /// A (lazy) server registrar. /// A (lazy) MainDom. public RuntimeState(ILogger logger, Lazy serverRegistrar, Lazy mainDom, IUmbracoSettingsSection settings, IGlobalSettings globalSettings) { _logger = logger; _serverRegistrar = serverRegistrar; _mainDom = mainDom; _settings = settings; _globalSettings = globalSettings; } private IServerRegistrar ServerRegistrar => _serverRegistrar.Value; /// /// Gets the application MainDom. /// /// This is NOT exposed in the interface as MainDom is internal. public MainDom MainDom => _mainDom.Value; /// /// Gets the version of the executing code. /// public Version Version => UmbracoVersion.Current; /// /// Gets the version comment of the executing code. /// public string VersionComment => UmbracoVersion.CurrentComment; /// /// Gets the semantic version of the executing code. /// public SemVersion SemanticVersion => UmbracoVersion.SemanticVersion; /// /// Gets a value indicating whether the application is running in debug mode. /// public bool Debug { get; } = GlobalSettings.DebugMode; /// /// Gets a value indicating whether the runtime is the current main domain. /// public bool IsMainDom => MainDom.IsMainDom; /// /// Get the server's current role. /// public ServerRole ServerRole => ServerRegistrar.GetCurrentServerRole(); /// /// Gets the Umbraco application url. /// /// This is eg "http://www.example.com". public Uri ApplicationUrl { get; private set; } /// /// Gets the Umbraco application virtual path. /// /// This is either "/" or eg "/virtual". public string ApplicationVirtualPath { get; } = HttpRuntime.AppDomainAppVirtualPath; /// public string CurrentMigrationState { get; internal set; } /// public string FinalMigrationState { get; internal set; } /// /// Gets the runtime level of execution. /// public RuntimeLevel Level { get => _level; internal set { _level = value; if (value == RuntimeLevel.Run) _runLevel.Set(); } } /// /// Ensures that the property has a value. /// /// internal void EnsureApplicationUrl(HttpRequestBase request = null) { // see U4-10626 - in some cases we want to reset the application url // (this is a simplified version of what was in 7.x) // note: should this be optional? is it expensive? var url = request == null ? null : ApplicationUrlHelper.GetApplicationUrlFromCurrentRequest(request, _globalSettings); var change = url != null && !_applicationUrls.Contains(url); if (change) { _logger.Info(typeof(ApplicationUrlHelper), "New url {Url} detected, re-discovering application url.", url); _applicationUrls.Add(url); } if (ApplicationUrl != null && !change) return; ApplicationUrl = new Uri(ApplicationUrlHelper.GetApplicationUrl(_logger, _globalSettings, _settings, ServerRegistrar, request)); } private readonly ManualResetEventSlim _runLevel = new ManualResetEventSlim(false); /// /// Waits for the runtime level to become RuntimeLevel.Run. /// /// A timeout. /// True if the runtime level became RuntimeLevel.Run before the timeout, otherwise false. internal bool WaitForRunLevel(TimeSpan timeout) { return _runLevel.WaitHandle.WaitOne(timeout); } /// /// Gets the exception that caused the boot to fail. /// public BootFailedException BootFailedException { get; internal set; } } }