Пример #1
0
        private bool reinitialize()
        {
            // If we are already initialized and the settings file hasn’t changed, we don’t need to do anything.
            var firstRunEver = _server == null;

            if (_server != null && File.GetLastWriteTimeUtc(_settingsPath) <= _settingsLastChangedTime)
            {
                return(false);
            }

            // This may load *and re-write* the settings file...
            var newSettings = PropellerUtil.LoadSettings(_settingsPath, firstRunEver ? new ConsoleLogger() : _log, firstRunEver);

            // ... so remember the file date/time stamp *after* the writing
            _settingsLastChangedTime = File.GetLastWriteTimeUtc(_settingsPath);

            _log = PropellerUtil.GetLogger(true, newSettings.LogFile, newSettings.LogVerbosity);
            _log.Info(firstRunEver ? "Initializing Propeller" : "Reinitializing Propeller");

            // If either port number or the bind-to address have changed, stop and restart the server’s listener.
            var startListening = false;

            if (_server == null || CurrentSettings == null ||
                !CurrentSettings.ServerOptions.Endpoints.Values.SequenceEqual(newSettings.ServerOptions.Endpoints.Values))
            {
                var removed = CurrentSettings == null ? new HttpEndpoint[0] : CurrentSettings.ServerOptions.Endpoints.Values.Except(newSettings.ServerOptions.Endpoints.Values).ToArray();
                var added   = CurrentSettings == null?newSettings.ServerOptions.Endpoints.Values.ToArray() : newSettings.ServerOptions.Endpoints.Values.Except(CurrentSettings.ServerOptions.Endpoints.Values).ToArray();

                if (_server == null || removed.Length > 0 || added.Length > 0)
                {
                    if (removed.Length > 0)
                    {
                        _log.Info("Disabling {0}".Fmt(removed.Select(ep => "HTTP{0} on port {1}".Fmt(ep.Secure ? "S" : null, ep.Port)).JoinString(", ", lastSeparator: " and ")));
                    }
                    if (added.Length > 0)
                    {
                        _log.Info("Enabling {0}".Fmt(added.Select(ep => "HTTP{0} on port {1}".Fmt(ep.Secure ? "S" : null, ep.Port)).JoinString(", ", lastSeparator: " and ")));
                    }

                    if (_server == null)
                    {
                        _server = new HttpServer
                        {
                            Options                  = newSettings.ServerOptions,
                            ErrorHandler             = errorHandler,
                            ResponseExceptionHandler = responseExceptionHandler
                        }
                    }
                    ;
                    else
                    {
                        _server.StopListening();
                    }
                    startListening = true;
                }
            }

            CurrentSettings = newSettings;

            // Create a new instance of all the modules
            var newAppDomains = new HashSet <AppDomainInfo>();

            foreach (var module in newSettings.Modules)
            {
                _log.Info("Initializing module: " + module.ModuleName);
                try
                {
                    var inf = new AppDomainInfo(_log, newSettings, module, new SettingsSaver(s =>
                    {
                        module.Settings        = s;
                        _settingsSavedByModule = true;
                    }));
                    newAppDomains.Add(inf);
                }
                catch (Exception e)
                {
                    _log.Error("Failed to initialize module {0}:".Fmt(module.ModuleName));
                    _log.Exception(e);
                }
            }

            // Switcheroo!
            lock (_lockObject)
            {
                _log.Info("AppDomain Switcheroo");
                _inactiveAppDomains.AddRange(_activeAppDomains);
                _activeAppDomains = newAppDomains;
                _server.Options   = newSettings.ServerOptions;
                _server.Handler   = createResolver().Handle;
                _server.Log       = PropellerUtil.GetLogger(newSettings.HttpAccessLogToConsole, newSettings.HttpAccessLogFile, newSettings.HttpAccessLogVerbosity);
                if (startListening)
                {
                    _server.StartListening();
                }
            }

            // Delete any remaining temp folders no longer in use
            HashSet <string> tempFoldersInUse;

            lock (_lockObject)
                tempFoldersInUse = _activeAppDomains.Concat(_inactiveAppDomains).Select(ad => ad.TempPathUsed).ToHashSet();
            foreach (var tempFolder in Directory.EnumerateDirectories(CurrentSettings.TempFolder ?? Path.GetTempPath(), "propeller-tmp-*"))
            {
                if (tempFoldersInUse.Contains(tempFolder))
                {
                    continue;
                }
                try { Directory.Delete(tempFolder, recursive: true); }
                catch { }
            }

            return(true);
        }
Пример #2
0
        private void checkSettingsChanges()
        {
            try
            {
                // ① If the server settings have changed, reinitialize everything.
                if (reinitialize())
                {
                    return;
                }

                // ② If a module rewrote its settings, save the settings file.
                if (_settingsSavedByModule)
                {
                    _log.Debug("A module saved the settings.");
                    try
                    {
                        lock (_lockObject)
                            CurrentSettings.Save(_settingsPath);
                    }
                    catch (Exception e)
                    {
                        _log.Error("Error saving Propeller settings:");
                        PropellerUtil.LogException(_log, e);
                    }
                    _settingsSavedByModule   = false;
                    _settingsLastChangedTime = File.GetLastWriteTimeUtc(_settingsPath);
                }

                // ③ If any module wants to reinitialize, do it
                AppDomainInfo[] actives;
                lock (_lockObject)
                    actives = _activeAppDomains.ToArray();
                foreach (var active in actives)
                {
                    if (!active.MustReinitialize)   // this adds a log message if it returns true
                    {
                        continue;
                    }
                    _log.Info("Module says it must reinitialize: {0} ({1})".Fmt(active.ModuleSettings.ModuleName, active.GetHashCode()));
                    var newAppDomain = new AppDomainInfo(_log, CurrentSettings, active.ModuleSettings, active.Saver);
                    lock (_lockObject)
                    {
                        _inactiveAppDomains.Add(active);
                        _activeAppDomains.Remove(active);
                        _activeAppDomains.Add(newAppDomain);
                        _server.Handler = createResolver().Handle;
                        _log.Info(" --- {0} replaced with {1}, {0} shutting down".Fmt(active.GetHashCode(), newAppDomain.GetHashCode()));
                        active.RunnerProxy.Shutdown();
                    }
                }

                // ④ Try to clean up as many inactive AppDomains as possible
                AppDomainInfo[] inactives;
                lock (_lockObject)
                    inactives = _inactiveAppDomains.ToArray();
                foreach (var inactive in inactives)
                {
                    // Ask the runner if it has active connections; if this throws, it’s in a broken state anyway, so unload it by force.
                    bool disposeAllowed;
                    try { disposeAllowed = inactive.HasActiveConnections; }
                    catch { disposeAllowed = true; }

                    if (disposeAllowed)
                    {
                        _log.Info("Disposing inactive module: {0} ({1})".Fmt(inactive.ModuleSettings.ModuleName, inactive.GetHashCode()));
                        lock (_lockObject)
                            _inactiveAppDomains.Remove(inactive);
                        try { inactive.Dispose(); }
                        catch { }
                    }
                    else
                    {
                        _log.Info("Inactive module still has active connections: {0} ({1})".Fmt(inactive.ModuleSettings.ModuleName, inactive.GetHashCode()));
                    }
                }
            }
            catch (Exception e)
            {
                PropellerUtil.LogException(_log, e);
            }
        }