diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs index 6274a71db..d902ed241 100644 --- a/Duplicati/Server/Program.cs +++ b/Duplicati/Server/Program.cs @@ -43,25 +43,45 @@ namespace Duplicati.Server { public class Program { + /// The commandline argument name for parameters file. private const string PARAMETERS_FILE_OPTION = "parameters-file"; + /// Alternative names for the parameters file option. private static readonly string[] PARAMETERS_FILE_OPTION_EXTRAS = ["parameterfile"]; + /// The commandline argument name for ping-pong keepalive. private const string PING_PONG_KEEPALIVE_OPTION = "ping-pong-keepalive"; + /// The commandline argument name for Windows event log. private const string WINDOWS_EVENTLOG_OPTION = "windows-eventlog"; + /// The commandline argument name for Windows event log level. private const string WINDOWS_EVENTLOG_LEVEL_OPTION = "windows-eventlog-level"; + /// The commandline argument name for disabling database encryption. private const string DISABLE_DB_ENCRYPTION_OPTION = "disable-db-encryption"; + /// The commandline argument name for requiring database encryption key. private const string REQUIRE_DB_ENCRYPTION_KEY_OPTION = "require-db-encryption-key"; + /// The commandline argument name for settings encryption key. private const string SETTINGS_ENCRYPTION_KEY_OPTION = "settings-encryption-key"; + /// The commandline argument name for disabling update check. private const string DISABLE_UPDATE_CHECK_OPTION = "disable-update-check"; + /// The commandline argument name for registering remote control. private const string REGISTER_REMOTE_CONTROL_OPTION = "register-remote-control"; + /// The commandline argument name for forcing remote control reregistration. private const string REGISTER_REMOTE_CONTROL_REREGISTER_OPTION = "register-remote-control-force"; + /// The commandline argument name for allowed backend modules. private const string ALLOWED_BACKEND_MODULES = "allowed-backend-modules"; + /// The commandline argument name for allowed encryption modules. private const string ALLOWED_ENCRYPTION_MODULES = "allowed-encryption-modules"; + /// The commandline argument name for allowed compression modules. private const string ALLOWED_COMPRESSION_MODULES = "allowed-compression-modules"; + /// The commandline argument name for log file. private const string LOG_FILE_OPTION = "log-file"; + /// The commandline argument name for log level. private const string LOG_LEVEL_OPTION = "log-level"; + /// The commandline argument name for log console. private const string LOG_CONSOLE_OPTION = "log-console"; + /// The commandline argument name for temp directory. private const string TEMPDIR_OPTION = "tempdir"; + /// The commandline argument name for log retention. private const string LOG_RETENTION_OPTION = "log-retention"; + /// The commandline argument name for help. private const string HELP_OPTION = "help"; @@ -182,8 +202,7 @@ namespace Duplicati.Server { string filename = commandlineOptions[parameterFileOption]; commandlineOptions.Remove(parameterFileOption); - if (!ReadOptionsFromFile(filename, ref filter, args, commandlineOptions)) - return 100; + ReadOptionsFromFile(filename, ref filter, args, commandlineOptions); } var logHandler = new LogWriteHandler(); @@ -365,6 +384,14 @@ namespace Duplicati.Server return 0; } + /// + /// Starts the Duplicati web server + /// + /// The commandline options + /// The connection to use + /// The log write handler + /// The application settings + /// private static async Task StartWebServer(IReadOnlyDictionary options, Connection connection, ILogWriteHandler logWriteHandler, IApplicationSettings applicationSettings) { var server = await WebServerLoader.TryRunServer(options, connection, async parsedOptions => @@ -399,6 +426,11 @@ namespace Duplicati.Server return server; } + /// + /// Sets up the timer for purging temp files and log data + /// + /// The connection to use + /// The commandline options private static void SetPurgeTempFilesTimer(Connection connection, Dictionary commandlineOptions) { var lastPurge = new DateTime(0); @@ -454,6 +486,14 @@ namespace Duplicati.Server DEBUG_MODE ? TimeSpan.FromHours(1) : TimeSpan.FromDays(1)); } + /// + /// Registers the server for remote control + /// + /// The remote controller registration + /// The remote controller + /// The remote control URL + /// Whether to re-register + /// Callback to log messages to console private static void RegisterForRemoteControl(IRemoteControllerRegistration remoteControllerRegistration, IRemoteController remoteController, string remoteControlUrl, bool reRegister, Action logMessageToConsole) { if (remoteController.CanEnable) @@ -494,6 +534,11 @@ namespace Duplicati.Server }); } + /// + /// Adjusts the application settings based on commandline options + /// + /// The connection to use + /// The commandline options private static void AdjustApplicationSettings(Connection connection, Dictionary commandlineOptions) { // This clears the JWT config, and a new will be generated, invalidating all existing tokens @@ -550,6 +595,12 @@ namespace Duplicati.Server } } + /// + /// Emits warnings for configuration issues + /// + /// The connection + /// The application settings + /// The commandline options private static void EmitWarningsForConfigurationIssues(Connection connection, IApplicationSettings applicationSettings, Dictionary commandlineOptions) { // First, remove any pending notifications, if the issue is resolved @@ -618,7 +669,12 @@ namespace Duplicati.Server } } - private static void CreateApplicationInstance(string dataFolder, bool writeToConsoleOnExceptionw) + /// + /// Creates the application instance to ensure a single instance is running for the current user + /// + /// The data folder to use for single instance locking + /// Write to console on exception + private static void CreateApplicationInstance(string dataFolder, bool writeToConsoleOnException) { try { @@ -627,7 +683,7 @@ namespace Duplicati.Server } catch (Exception ex) { - if (writeToConsoleOnExceptionw) + if (writeToConsoleOnException) { Console.WriteLine(Strings.Program.StartupFailure(ex)); Environment.Exit(200); @@ -638,7 +694,7 @@ namespace Duplicati.Server if (!ApplicationInstance.IsFirstInstance) { - if (writeToConsoleOnExceptionw) + if (writeToConsoleOnException) { Console.WriteLine(Strings.Program.AnotherInstanceDetected); Environment.Exit(200); @@ -648,6 +704,10 @@ namespace Duplicati.Server } } + /// + /// Applies environment variables by converting them to commandline options + /// + /// The commandline options private static void ApplyEnvironmentVariables(Dictionary commandlineOptions) { foreach (var key in SupportedCommands.SelectMany(x => (x.Aliases ?? []).Prepend(x.Name)).Distinct()) @@ -667,11 +727,23 @@ namespace Duplicati.Server commandlineOptions[SETTINGS_ENCRYPTION_KEY_OPTION] = Environment.GetEnvironmentVariable(EncryptedFieldHelper.ENVIROMENT_VARIABLE_NAME); } + /// + /// Applies the secret provider to the commandline options and application settings + /// + /// The application settings + /// The commandline options + /// The cancellation token + /// A task that represents the asynchronous operation private static async Task ApplySecretProvider(IApplicationSettings applicationSettings, Dictionary commandlineOptions, CancellationToken cancellationToken) => applicationSettings.SecretProvider = await SecretProviderHelper.ApplySecretProviderAsync([], [], commandlineOptions, TempFolder.SystemTempPath, applicationSettings.SecretProvider, cancellationToken).ConfigureAwait(false); + /// + /// A log destination that writes to the console + /// + /// The minimum log level private class ConsoleLogDestination(LogMessageType level) : ILogDestination { + /// public void WriteMessage(LogEntry entry) { if (entry.Level >= level) @@ -679,6 +751,12 @@ namespace Duplicati.Server } } + /// + /// Configures logging based on commandline options + /// + /// The log write handler + /// The commandline options + /// A disposable log scope private static IDisposable ConfigureLogging(ILogWriteHandler logWriteHandler, Dictionary commandlineOptions) { IDisposable logScope; @@ -748,9 +826,14 @@ namespace Duplicati.Server return logScope; } - private static int ShowHelp(bool writeToConsoleOnExceptionw) + /// + /// Shows the help information + /// + /// Whether to write to console on exception + /// An integer indicating the result + private static int ShowHelp(bool writeToConsoleOnException) { - if (writeToConsoleOnExceptionw) + if (writeToConsoleOnException) { Console.WriteLine(Strings.Program.HelpDisplayDialog); @@ -763,6 +846,14 @@ namespace Duplicati.Server throw new Exception("Server invoked with --help"); } + /// + /// Gets the database connection, upgrading the database if needed + /// + /// The application settings + /// The commandline options + /// Whether to suppress console output + /// Whether to change the database encryption state if the arguments require it + /// The database connection public static Connection GetDatabaseConnection(IApplicationSettings applicationSettings, Dictionary commandlineOptions, bool silentConsole, bool changeDbEncryption) { // Emit a warning if the database is stored in the Windows folder @@ -858,6 +949,10 @@ namespace Duplicati.Server return new Connection(con, disableDbEncryption, encKey, applicationSettings.DataFolder, applicationSettings.StartOrStopUsageReporter); } + /// + /// Starts or stops the usage reporter based on application settings + /// + /// The connection private static void StartOrStopUsageReporter(Connection connection) { var disableUsageReporter = @@ -1001,7 +1096,15 @@ namespace Duplicati.Server /// public static readonly HashSet KnownDuplicateOptions = new HashSet(StringComparer.OrdinalIgnoreCase); - private static bool ReadOptionsFromFile(string filename, ref IFilter filter, List cargs, Dictionary options) + /// + /// Reads options from a file and applies them to the current commandline arguments and options + /// + /// The filename + /// The filter + /// The commandline arguments + /// The options + /// True if successful + private static void ReadOptionsFromFile(string filename, ref IFilter filter, List cargs, Dictionary options) { try { @@ -1078,8 +1181,6 @@ namespace Duplicati.Server cargs.AddRange(newsource); else if (newsource.Count > 0) Log.WriteVerboseMessage(LOGTAG, "NotUsingBackupSources", Strings.Program.SkippingSourceArgumentsOnNonBackupOperation); - - return true; } catch (Exception e) {