diff --git a/Duplicati.Library.RestAPI/BackupImportExportHandler.cs b/Duplicati.Library.RestAPI/BackupImportExportHandler.cs index 6c11b0b46..c1f6b569c 100644 --- a/Duplicati.Library.RestAPI/BackupImportExportHandler.cs +++ b/Duplicati.Library.RestAPI/BackupImportExportHandler.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Linq; +using Duplicati.Server.Database; using Duplicati.Server.Serialization; using Duplicati.Server.Serialization.Interface; @@ -14,9 +15,9 @@ public static class BackupImportExportHandler backup.SanitizeTargetUrl(); } - public static byte[] ExportToJSON(IBackup backup, string passphrase) + public static byte[] ExportToJSON(Connection connection, IBackup backup, string passphrase) { - Server.Serializable.ImportExportStructure ipx = FIXMEGlobal.DataConnection.PrepareBackupForExport(backup); + Server.Serializable.ImportExportStructure ipx = connection.PrepareBackupForExport(backup); byte[] data; using (var ms = new System.IO.MemoryStream()) diff --git a/Duplicati.Library.RestAPI/EventPollNotify.cs b/Duplicati.Library.RestAPI/EventPollNotify.cs index 777dc4a1e..4c32f1943 100644 --- a/Duplicati.Library.RestAPI/EventPollNotify.cs +++ b/Duplicati.Library.RestAPI/EventPollNotify.cs @@ -1,7 +1,5 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; namespace Duplicati.Server { diff --git a/Duplicati.Library.RestAPI/FIXMEGlobal.cs b/Duplicati.Library.RestAPI/FIXMEGlobal.cs index 730b5c79e..b034f8f4a 100644 --- a/Duplicati.Library.RestAPI/FIXMEGlobal.cs +++ b/Duplicati.Library.RestAPI/FIXMEGlobal.cs @@ -27,11 +27,6 @@ namespace Duplicati.Library.RestAPI /// public static Server.Database.Connection DataConnection; - /// - /// The controller interface for pause/resume and throttle options - /// - public static LiveControls LiveControl => Provider.GetRequiredService(); - /// /// A delegate method for creating a copy of the current progress state /// diff --git a/Duplicati.Library.RestAPI/Serializable/ServerStatus.cs b/Duplicati.Library.RestAPI/Serializable/ServerStatus.cs index df2a8f6e6..76f5f3ec5 100644 --- a/Duplicati.Library.RestAPI/Serializable/ServerStatus.cs +++ b/Duplicati.Library.RestAPI/Serializable/ServerStatus.cs @@ -29,21 +29,21 @@ namespace Duplicati.Server.Serializable /// /// This class collects all reportable status properties into a single class that can be exported as JSON /// - public class ServerStatus : Duplicati.Server.Serialization.Interface.IServerStatus + public class ServerStatus(LiveControls liveControls) : Duplicati.Server.Serialization.Interface.IServerStatus { public LiveControlState ProgramState { - get { return EnumConverter.Convert(FIXMEGlobal.LiveControl.State); } + get { return EnumConverter.Convert(liveControls.State); } } - public string UpdatedVersion - { - get - { + public string UpdatedVersion + { + get + { var u = FIXMEGlobal.DataConnection.ApplicationSettings.UpdatedVersion; if (u == null) return null; - + Version v; if (!Version.TryParse(u.Version, out v)) return null; @@ -51,7 +51,7 @@ namespace Duplicati.Server.Serializable if (v <= System.Reflection.Assembly.GetExecutingAssembly().GetName().Version) return null; - return u.Displayname; + return u.Displayname; } } @@ -64,8 +64,8 @@ namespace Duplicati.Server.Serializable public Tuple ActiveTask { - get - { + get + { var t = FIXMEGlobal.WorkThread.CurrentTask; if (t == null) return null; @@ -85,18 +85,18 @@ namespace Duplicati.Server.Serializable { return ( from n in FIXMEGlobal.Scheduler.Schedule - let backupid = (from t in n.Value.Tags - where t != null && t.StartsWith("ID=", StringComparison.Ordinal) - select t.Substring("ID=".Length)).FirstOrDefault() - where !string.IsNullOrWhiteSpace(backupid) - select new Tuple(backupid, n.Key) + let backupid = (from t in n.Value.Tags + where t != null && t.StartsWith("ID=", StringComparison.Ordinal) + select t.Substring("ID=".Length)).FirstOrDefault() + where !string.IsNullOrWhiteSpace(backupid) + select new Tuple(backupid, n.Key) ).ToList(); } } - + public bool HasWarning { get { return FIXMEGlobal.DataConnection.ApplicationSettings.UnackedWarning; } } public bool HasError { get { return FIXMEGlobal.DataConnection.ApplicationSettings.UnackedError; } } - + public SuggestedStatusIcon SuggestedStatusIcon { get @@ -105,12 +105,12 @@ namespace Duplicati.Server.Serializable { if (this.ProgramState == LiveControlState.Paused) return SuggestedStatusIcon.Paused; - + if (this.HasError) return SuggestedStatusIcon.ReadyError; if (this.HasWarning) return SuggestedStatusIcon.ReadyWarning; - + return SuggestedStatusIcon.Ready; } else @@ -123,18 +123,18 @@ namespace Duplicati.Server.Serializable } } - public DateTime EstimatedPauseEnd + public DateTime EstimatedPauseEnd { - get - { - return FIXMEGlobal.LiveControl.EstimatedPauseEnd; + get + { + return liveControls.EstimatedPauseEnd; } } private long m_lastEventID = FIXMEGlobal.StatusEventNotifyer.EventNo; - public long LastEventID - { + public long LastEventID + { get { return m_lastEventID; } set { m_lastEventID = value; } } diff --git a/Duplicati.Library.RestAPI/UpdatePollThread.cs b/Duplicati.Library.RestAPI/UpdatePollThread.cs index 5ed4a3a5b..6f0ce0ac7 100644 --- a/Duplicati.Library.RestAPI/UpdatePollThread.cs +++ b/Duplicati.Library.RestAPI/UpdatePollThread.cs @@ -22,7 +22,7 @@ using System; using System.Linq; using System.Threading; -using Duplicati.Library.RestAPI; +using Duplicati.Server.Database; using Duplicati.Server.Serialization; namespace Duplicati.Server @@ -30,7 +30,7 @@ namespace Duplicati.Server /// /// The thread that checks on the update server if new versions are available /// - public class UpdatePollThread + public class UpdatePollThread(Connection connection, EventPollNotify eventPollNotify) { private Thread m_thread; private volatile bool m_terminated = false; @@ -51,7 +51,7 @@ namespace Duplicati.Server var oldv = m_downloadProgress; m_downloadProgress = value; if ((int)(oldv * 100) != (int)(value * 100)) - FIXMEGlobal.StatusEventNotifyer.SignalNewEvent(); + eventPollNotify.SignalNewEvent(); } } @@ -97,12 +97,12 @@ namespace Duplicati.Server while (!m_terminated) { - var nextCheck = FIXMEGlobal.DataConnection.ApplicationSettings.NextUpdateCheck; + var nextCheck = connection.ApplicationSettings.NextUpdateCheck; var maxcheck = TimeSpan.FromDays(7); try { - maxcheck = Library.Utility.Timeparser.ParseTimeSpan(FIXMEGlobal.DataConnection.ApplicationSettings.UpdateCheckInterval); + maxcheck = Library.Utility.Timeparser.ParseTimeSpan(connection.ApplicationSettings.UpdateCheckInterval); } catch { @@ -118,14 +118,14 @@ namespace Duplicati.Server m_forceCheck = false; ThreadState = UpdatePollerStates.Checking; - FIXMEGlobal.StatusEventNotifyer.SignalNewEvent(); + eventPollNotify.SignalNewEvent(); DateTime started = DateTime.UtcNow; - FIXMEGlobal.DataConnection.ApplicationSettings.LastUpdateCheck = started; - nextCheck = FIXMEGlobal.DataConnection.ApplicationSettings.NextUpdateCheck; + connection.ApplicationSettings.LastUpdateCheck = started; + nextCheck = connection.ApplicationSettings.NextUpdateCheck; Library.AutoUpdater.ReleaseType rt; - if (!Enum.TryParse(FIXMEGlobal.DataConnection.ApplicationSettings.UpdateChannel, true, out rt)) + if (!Enum.TryParse(connection.ApplicationSettings.UpdateChannel, true, out rt)) rt = Duplicati.Library.AutoUpdater.ReleaseType.Unknown; // Choose the default channel in case we have unknown @@ -135,7 +135,7 @@ namespace Duplicati.Server { var update = Duplicati.Library.AutoUpdater.UpdaterManager.CheckForUpdate(rt); if (update != null) - FIXMEGlobal.DataConnection.ApplicationSettings.UpdatedVersion = update; + connection.ApplicationSettings.UpdatedVersion = update; } catch { @@ -144,10 +144,10 @@ namespace Duplicati.Server // It could be that we have registered an update from a more unstable channel, // but the user has switched to a more stable channel. // In that case we discard the old update to avoid offering it. - if (FIXMEGlobal.DataConnection.ApplicationSettings.UpdatedVersion != null) + if (connection.ApplicationSettings.UpdatedVersion != null) { Library.AutoUpdater.ReleaseType updatert; - var updatertstring = FIXMEGlobal.DataConnection.ApplicationSettings.UpdatedVersion.ReleaseType; + var updatertstring = connection.ApplicationSettings.UpdatedVersion.ReleaseType; if (string.Equals(updatertstring, "preview", StringComparison.OrdinalIgnoreCase)) updatertstring = Library.AutoUpdater.ReleaseType.Experimental.ToString(); @@ -158,15 +158,15 @@ namespace Duplicati.Server updatert = Duplicati.Library.AutoUpdater.ReleaseType.Nightly; if (updatert > rt) - FIXMEGlobal.DataConnection.ApplicationSettings.UpdatedVersion = null; + connection.ApplicationSettings.UpdatedVersion = null; } - var updatedinfo = FIXMEGlobal.DataConnection.ApplicationSettings.UpdatedVersion; + var updatedinfo = connection.ApplicationSettings.UpdatedVersion; if (updatedinfo != null && Duplicati.Library.AutoUpdater.UpdaterManager.TryParseVersion(updatedinfo.Version) > System.Reflection.Assembly.GetExecutingAssembly().GetName().Version) { var package = updatedinfo.FindPackage(); - FIXMEGlobal.DataConnection.RegisterNotification( + connection.RegisterNotification( NotificationType.Information, "Found update", updatedinfo.Displayname, @@ -189,7 +189,7 @@ namespace Duplicati.Server if (ThreadState != UpdatePollerStates.Waiting) { ThreadState = UpdatePollerStates.Waiting; - FIXMEGlobal.StatusEventNotifyer.SignalNewEvent(); + eventPollNotify.SignalNewEvent(); } var waitTime = nextCheck - DateTime.UtcNow; diff --git a/Duplicati/Server/Program.cs b/Duplicati/Server/Program.cs index d17337701..c9166a7e1 100644 --- a/Duplicati/Server/Program.cs +++ b/Duplicati/Server/Program.cs @@ -26,6 +26,7 @@ using System.Threading.Tasks; using Duplicati.Library.Common; using Duplicati.Library.Common.IO; using Duplicati.Library.RestAPI; +using Duplicati.Server.Database; using Duplicati.WebserverCore; using Duplicati.WebserverCore.Abstractions; using Microsoft.Extensions.DependencyInjection; @@ -263,7 +264,7 @@ namespace Duplicati.Server DataConnection.LogError(null, "Error in updater", obj); }; - DuplicatiWebserver = StartWebServer(commandlineOptions).ConfigureAwait(false).GetAwaiter().GetResult(); + DuplicatiWebserver = StartWebServer(commandlineOptions, DataConnection).ConfigureAwait(false).GetAwaiter().GetResult(); UpdatePoller.Init(); @@ -325,9 +326,9 @@ namespace Duplicati.Server return 0; } - private static async Task StartWebServer(IReadOnlyDictionary options) + private static async Task StartWebServer(IReadOnlyDictionary options, Connection connection) { - var server = await WebServerLoader.TryRunServer(options, async parsedOptions => + var server = await WebServerLoader.TryRunServer(options, connection, async parsedOptions => { var mappedSettings = new DuplicatiWebserver.InitSettings( parsedOptions.WebRoot, @@ -340,7 +341,7 @@ namespace Duplicati.Server var server = new DuplicatiWebserver(); - server.InitWebServer(mappedSettings, DataConnection); + server.InitWebServer(mappedSettings, connection); server.Start(mappedSettings); return server; }).ConfigureAwait(false); diff --git a/Duplicati/Server/WebServerLoader.cs b/Duplicati/Server/WebServerLoader.cs index 83b350a5b..80158f271 100644 --- a/Duplicati/Server/WebServerLoader.cs +++ b/Duplicati/Server/WebServerLoader.cs @@ -4,6 +4,7 @@ using System.Linq; using System.Security.Cryptography.X509Certificates; using System.Threading.Tasks; using Duplicati.Library.RestAPI; +using Duplicati.Server.Database; namespace Duplicati.Server; @@ -93,7 +94,7 @@ public static class WebServerLoader /// /// A set of options /// The method to start the server - public static async Task TryRunServer(IReadOnlyDictionary options, Func> createServer) + public static async Task TryRunServer(IReadOnlyDictionary options, Connection connection, Func> createServer) { var ports = Enumerable.Empty(); options.TryGetValue(OPTION_PORT, out var portstring); @@ -109,7 +110,7 @@ public static class WebServerLoader options.TryGetValue(OPTION_INTERFACE, out var interfacestring); if (string.IsNullOrWhiteSpace(interfacestring)) - interfacestring = FIXMEGlobal.DataConnection.ApplicationSettings.ServerListenInterface; + interfacestring = connection.ApplicationSettings.ServerListenInterface; if (string.IsNullOrWhiteSpace(interfacestring)) interfacestring = DEFAULT_OPTION_INTERFACE; @@ -129,7 +130,7 @@ public static class WebServerLoader { try { - cert = FIXMEGlobal.DataConnection.ApplicationSettings.ServerSSLCertificate; + cert = connection.ApplicationSettings.ServerSSLCertificate; } catch (Exception ex) { @@ -138,7 +139,7 @@ public static class WebServerLoader } else if (certificateFile.Length == 0) { - FIXMEGlobal.DataConnection.ApplicationSettings.ServerSSLCertificate = null; + connection.ApplicationSettings.ServerSSLCertificate = null; } else { @@ -197,11 +198,11 @@ public static class WebServerLoader settings = settings with { Port = p }; var server = await createServer(settings); - if (interfacestring != FIXMEGlobal.DataConnection.ApplicationSettings.ServerListenInterface) - FIXMEGlobal.DataConnection.ApplicationSettings.ServerListenInterface = interfacestring; + if (interfacestring != connection.ApplicationSettings.ServerListenInterface) + connection.ApplicationSettings.ServerListenInterface = interfacestring; - if (certValid && cert != FIXMEGlobal.DataConnection.ApplicationSettings.ServerSSLCertificate) - FIXMEGlobal.DataConnection.ApplicationSettings.ServerSSLCertificate = cert; + if (certValid && cert != connection.ApplicationSettings.ServerSSLCertificate) + connection.ApplicationSettings.ServerSSLCertificate = cert; Duplicati.Library.Logging.Log.WriteInformationMessage(LOGTAG, "ServerListening", Duplicati.Server.Strings.Server.StartedServer(listenInterface.ToString(), p)); diff --git a/Duplicati/UnitTest/ImportExportTests.cs b/Duplicati/UnitTest/ImportExportTests.cs index 590ad88ac..23b86a0e0 100644 --- a/Duplicati/UnitTest/ImportExportTests.cs +++ b/Duplicati/UnitTest/ImportExportTests.cs @@ -107,7 +107,7 @@ namespace Duplicati.UnitTest byte[] jsonByteArray; using (Program.DataConnection = Program.GetDatabaseConnection(advancedOptions)) { - jsonByteArray = BackupImportExportHandler.ExportToJSON(backup, null); + jsonByteArray = BackupImportExportHandler.ExportToJSON(Program.DataConnection, backup, null); } // The username should not have the '%40' converted to '@' since the import code @@ -131,14 +131,14 @@ namespace Duplicati.UnitTest { // Unencrypted file, don't import metadata. string unencryptedWithoutMetadata = Path.Combine(this.serverDatafolder, Path.GetRandomFileName()); - File.WriteAllBytes(unencryptedWithoutMetadata, BackupImportExportHandler.ExportToJSON(this.CreateBackup("unencrypted without metadata", "user", "password", metadata), null)); + File.WriteAllBytes(unencryptedWithoutMetadata, BackupImportExportHandler.ExportToJSON(Program.DataConnection, this.CreateBackup("unencrypted without metadata", "user", "password", metadata), null)); BackupImportExportHandler.ImportBackup(unencryptedWithoutMetadata, false, () => null, advancedOptions); Assert.AreEqual(1, Program.DataConnection.Backups.Length); Assert.AreEqual(0, Program.DataConnection.Backups[0].Metadata.Count); // Unencrypted file, import metadata. string unencryptedWithMetadata = Path.Combine(this.serverDatafolder, Path.GetRandomFileName()); - File.WriteAllBytes(unencryptedWithMetadata, BackupImportExportHandler.ExportToJSON(this.CreateBackup("unencrypted with metadata", "user", "password", metadata), null)); + File.WriteAllBytes(unencryptedWithMetadata, BackupImportExportHandler.ExportToJSON(Program.DataConnection, this.CreateBackup("unencrypted with metadata", "user", "password", metadata), null)); BackupImportExportHandler.ImportBackup(unencryptedWithMetadata, true, () => null, advancedOptions); Assert.AreEqual(2, Program.DataConnection.Backups.Length); Assert.AreEqual(metadata.Count, Program.DataConnection.Backups[1].Metadata.Count); @@ -146,14 +146,14 @@ namespace Duplicati.UnitTest // Encrypted file, don't import metadata. string encryptedWithoutMetadata = Path.Combine(this.serverDatafolder, Path.GetRandomFileName()); string passphrase = "abcde"; - File.WriteAllBytes(encryptedWithoutMetadata, BackupImportExportHandler.ExportToJSON(this.CreateBackup("encrypted without metadata", "user", "password", metadata), passphrase)); + File.WriteAllBytes(encryptedWithoutMetadata, BackupImportExportHandler.ExportToJSON(Program.DataConnection, this.CreateBackup("encrypted without metadata", "user", "password", metadata), passphrase)); BackupImportExportHandler.ImportBackup(encryptedWithoutMetadata, false, () => passphrase, advancedOptions); Assert.AreEqual(3, Program.DataConnection.Backups.Length); Assert.AreEqual(0, Program.DataConnection.Backups[2].Metadata.Count); // Encrypted file, import metadata. string encryptedWithMetadata = Path.Combine(this.serverDatafolder, Path.GetRandomFileName()); - File.WriteAllBytes(encryptedWithMetadata, BackupImportExportHandler.ExportToJSON(this.CreateBackup("encrypted with metadata", "user", "password", metadata), passphrase)); + File.WriteAllBytes(encryptedWithMetadata, BackupImportExportHandler.ExportToJSON(Program.DataConnection, this.CreateBackup("encrypted with metadata", "user", "password", metadata), passphrase)); BackupImportExportHandler.ImportBackup(encryptedWithMetadata, true, () => passphrase, advancedOptions); Assert.AreEqual(4, Program.DataConnection.Backups.Length); Assert.AreEqual(metadata.Count, Program.DataConnection.Backups[3].Metadata.Count); diff --git a/Duplicati/WebserverCore/DuplicatiWebserver.cs b/Duplicati/WebserverCore/DuplicatiWebserver.cs index 75f146b29..4d675398f 100644 --- a/Duplicati/WebserverCore/DuplicatiWebserver.cs +++ b/Duplicati/WebserverCore/DuplicatiWebserver.cs @@ -78,8 +78,6 @@ public partial class DuplicatiWebserver .AddHostedService() .AddEndpointsApiExplorer() .AddSwaggerGen() - .AddSingleton(connection) - .AddSingleton() .AddHttpContextAccessor() .AddAntiforgery(options => { @@ -88,7 +86,7 @@ public partial class DuplicatiWebserver options.FormFieldName = "x-xsrf-token"; }); - builder.Services.AddDuplicati(); + builder.Services.AddDuplicati(connection); Configuration = builder.Configuration; App = builder.Build(); diff --git a/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupPutDelete.cs b/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupPutDelete.cs index 4b9ed7280..ae73f2cb0 100644 --- a/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupPutDelete.cs +++ b/Duplicati/WebserverCore/Endpoints/V1/Backup/BackupPutDelete.cs @@ -1,4 +1,5 @@ using System.Text.Json; +using Duplicati.Library.IO; using Duplicati.Library.RestAPI; using Duplicati.Library.RestAPI.Abstractions; using Duplicati.Server; @@ -33,9 +34,9 @@ public class BackupPutDelete : IEndpointV1 }); - group.MapDelete("/backup/{id}", ([FromServices] Connection connection, [FromServices] IWorkerThreadsManager workerThreadsManager, [FromServices] ICaptchaProvider captchaProvider, [FromServices] IHttpContextAccessor httpContextAccessor, [FromRoute] string id, [FromQuery] bool? delete_remote_files, [FromQuery] bool? delete_local_db, [FromQuery] string captcha_token, [FromQuery] string captcha_answer, [FromQuery] bool force) => + group.MapDelete("/backup/{id}", ([FromServices] Connection connection, [FromServices] IWorkerThreadsManager workerThreadsManager, [FromServices] ICaptchaProvider captchaProvider, [FromServices] LiveControls liveControls, [FromServices] IHttpContextAccessor httpContextAccessor, [FromRoute] string id, [FromQuery] bool? delete_remote_files, [FromQuery] bool? delete_local_db, [FromQuery] string captcha_token, [FromQuery] string captcha_answer, [FromQuery] bool force) => { - var res = ExecuteDelete(GetBackup(connection, id), connection, workerThreadsManager, captchaProvider, delete_remote_files ?? false, delete_local_db, captcha_token, captcha_answer, force); + var res = ExecuteDelete(GetBackup(connection, id), connection, workerThreadsManager, captchaProvider, liveControls, delete_remote_files ?? false, delete_local_db, captcha_token, captcha_answer, force); if (res.Status != "OK" && httpContextAccessor.HttpContext != null) httpContextAccessor.HttpContext.Response.StatusCode = 500; return res; @@ -127,7 +128,7 @@ public class BackupPutDelete : IEndpointV1 } } - private static Dto.DeleteBackupOutputDto ExecuteDelete(IBackup backup, Connection connection, IWorkerThreadsManager workerThreadsManager, ICaptchaProvider captchaProvider, bool delete_remote_files, bool? delete_local_db, string captcha_token, string captcha_answer, bool force) + private static Dto.DeleteBackupOutputDto ExecuteDelete(IBackup backup, Connection connection, IWorkerThreadsManager workerThreadsManager, ICaptchaProvider captchaProvider, LiveControls liveControls, bool delete_remote_files, bool? delete_local_db, string captcha_token, string captcha_answer, bool force) { if (delete_remote_files) { @@ -151,8 +152,8 @@ public class BackupPutDelete : IEndpointV1 return new Dto.DeleteBackupOutputDto("failed", "backup-in-progress", nt?.TaskID); - bool hasPaused = FIXMEGlobal.LiveControl.State == LiveControls.LiveControlState.Paused; - FIXMEGlobal.LiveControl.Pause(); + bool hasPaused = liveControls.State == LiveControls.LiveControlState.Paused; + liveControls.Pause(); for (int i = 0; i < 10; i++) if (workerThreadsManager.WorkerThread.Active) @@ -172,14 +173,14 @@ public class BackupPutDelete : IEndpointV1 if (backup.Equals(t == null ? null : t.Backup)) { if (hasPaused) - FIXMEGlobal.LiveControl.Resume(); + liveControls.Resume(); return new Dto.DeleteBackupOutputDto("failed", "backup-unstoppable", t?.TaskID); } } if (hasPaused) - FIXMEGlobal.LiveControl.Resume(); + liveControls.Resume(); } } catch (Exception ex) diff --git a/Duplicati/WebserverCore/Endpoints/V1/ServerState.cs b/Duplicati/WebserverCore/Endpoints/V1/ServerState.cs index f67509d63..93f7794d3 100644 --- a/Duplicati/WebserverCore/Endpoints/V1/ServerState.cs +++ b/Duplicati/WebserverCore/Endpoints/V1/ServerState.cs @@ -1,4 +1,5 @@ using Duplicati.Library.RestAPI; +using Duplicati.Server; using Duplicati.WebserverCore.Abstractions; using Duplicati.WebserverCore.Exceptions; using Microsoft.AspNetCore.Mvc; @@ -12,8 +13,8 @@ public class ServerState : IEndpointV1 group.MapGet("/serverstate", ([FromQuery] long? lastEventId, [FromQuery] bool? longpoll, string? duration, [FromServices] IStatusService statusService) => Execute(lastEventId, longpoll, duration, statusService)); - group.MapPost("/serverstate/pause", ([FromServices] IStatusService statusService, [FromQuery] string? duration) => ExecutePause(statusService, duration)); - group.MapPost("/serverstate/resume", ([FromServices] IStatusService statusService) => ExecuteResume(statusService)); + group.MapPost("/serverstate/pause", ([FromServices] IStatusService statusService, [FromServices] LiveControls liveControls, [FromQuery] string? duration) => ExecutePause(statusService, liveControls, duration)); + group.MapPost("/serverstate/resume", ([FromServices] IStatusService statusService, [FromServices] LiveControls liveControls) => ExecuteResume(statusService, liveControls)); } private static Dto.ServerStatusDto Execute(long? lastEventId, bool? longpoll, string? duration, IStatusService statusService) @@ -42,7 +43,7 @@ public class ServerState : IEndpointV1 return status; } - private static void ExecutePause(IStatusService statusService, string? duration) + private static void ExecutePause(IStatusService statusService, LiveControls liveControls, string? duration) { var ts = TimeSpan.Zero; if (duration != null) @@ -50,13 +51,13 @@ public class ServerState : IEndpointV1 catch { throw new BadRequestException("The duration must be a valid time span"); } if (ts.TotalMilliseconds > 0) - FIXMEGlobal.LiveControl.Pause(ts); + liveControls.Pause(ts); else - FIXMEGlobal.LiveControl.Pause(); + liveControls.Pause(); } - private static void ExecuteResume(IStatusService statusService) + private static void ExecuteResume(IStatusService statusService, LiveControls liveControls) { - FIXMEGlobal.LiveControl.Resume(); + liveControls.Resume(); } } \ No newline at end of file diff --git a/Duplicati/WebserverCore/Extensions/ServiceCollectionsExtensions.cs b/Duplicati/WebserverCore/Extensions/ServiceCollectionsExtensions.cs index 047c62661..6c734c7fc 100644 --- a/Duplicati/WebserverCore/Extensions/ServiceCollectionsExtensions.cs +++ b/Duplicati/WebserverCore/Extensions/ServiceCollectionsExtensions.cs @@ -2,6 +2,7 @@ using Duplicati.Library.IO; using Duplicati.Library.RestAPI; using Duplicati.Library.RestAPI.Abstractions; using Duplicati.Server; +using Duplicati.Server.Database; using Duplicati.Server.Serialization; using Duplicati.WebserverCore.Abstractions; using Duplicati.WebserverCore.Abstractions.Notifications; @@ -14,13 +15,17 @@ namespace Duplicati.WebserverCore.Extensions; public static class ServiceCollectionsExtensions { - public static IServiceCollection AddDuplicati(this IServiceCollection services) + public static IServiceCollection AddDuplicati(this IServiceCollection services, Connection connection) { //old part - services.AddSingleton(); - services.AddSingleton(Serializer.JsonSettings); - services.AddSingleton(); - services.AddSingleton(); + services + .AddSingleton() + .AddSingleton(Serializer.JsonSettings) + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton(connection); + //transitional part - services that act as a proxy to old part for various reasons (not accessible in assembly i.e.) services.AddSingleton(c => c.GetRequiredService());