diff --git a/Duplicati/Library/DynamicLoader/WebLoader.cs b/Duplicati/Library/DynamicLoader/WebLoader.cs new file mode 100644 index 000000000..993730193 --- /dev/null +++ b/Duplicati/Library/DynamicLoader/WebLoader.cs @@ -0,0 +1,66 @@ +// Copyright (C) 2014, Kenneth Skovhede + +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.Collections.Generic; +using System.Text; +using Duplicati.Library.Interface; + +namespace Duplicati.Library.DynamicLoader +{ + public static class WebLoader + { + /// + /// Implementation overrides specific to encryption + /// + private class WebLoaderSub : DynamicLoader + { + /// + /// Returns the filename extension, which is also the key + /// + /// The item to load the key for + /// The file extension used by the module + protected override string GetInterfaceKey(IWebModule item) + { + return item.Key; + } + + /// + /// Returns the subfolders searched for encryption modules + /// + protected override string[] Subfolders + { + get { return new string[] { "webmodules" }; } + } + } + + #region Public static API + + /// + /// Gets a list of loaded settings controls, the instances can be used to extract interface information, not used to interact with the module. + /// + public static IWebModule[] Modules { get { return new WebLoaderSub().Interfaces; } } + + /// + /// Gets a list of keys supported + /// + public static string[] Keys { get { return new WebLoaderSub().Keys; } } + + #endregion + } +} + diff --git a/Duplicati/Library/Interface/IWebModule.cs b/Duplicati/Library/Interface/IWebModule.cs new file mode 100644 index 000000000..5237aef2e --- /dev/null +++ b/Duplicati/Library/Interface/IWebModule.cs @@ -0,0 +1,54 @@ +// Copyright (C) 2014, Kenneth Skovhede + +// http://www.hexad.dk, opensource@hexad.dk +// +// This library is free software; you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as +// published by the Free Software Foundation; either version 2.1 of the +// License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, but +// WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +using System; +using System.Collections.Generic; + +namespace Duplicati.Library.Interface +{ + public interface IWebModule + { + /// + /// The module key, used to activate or deactivate the module on the commandline + /// + string Key { get; } + + /// + /// A localized string describing the module with a friendly name + /// + string DisplayName { get; } + + /// + /// A localized description of the module + /// + string Description { get; } + + /// + /// Gets a list of supported commandline arguments + /// + IList SupportedCommands { get; } + + /// + /// Execute the specified command with the given options. + /// + /// The command to execute + /// The options to use + IDictionary Execute(string command, IDictionary options); + + } +} + diff --git a/Duplicati/Server/WebServer.cs b/Duplicati/Server/WebServer.cs index 613eddf25..bd371eaca 100644 --- a/Duplicati/Server/WebServer.cs +++ b/Duplicati/Server/WebServer.cs @@ -233,6 +233,7 @@ namespace Duplicati.Server SUPPORTED_METHODS.Add("delete-backup", DeleteBackup); SUPPORTED_METHODS.Add("validate-path", ValidatePath); SUPPORTED_METHODS.Add("list-tags", ListTags); + SUPPORTED_METHODS.Add("test-backend", TestBackend); } public override bool Process (HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session) @@ -302,6 +303,28 @@ namespace Duplicati.Server Serializer.SerializeJson(b, o); } + private void TestBackend(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw) + { + HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString; + if (input["url"] == null || input["url"].Value == null) + { + ReportError(response, bw, "The path parameter was not set"); + return; + } + + try + { + using(var b = Duplicati.Library.DynamicLoader.BackendLoader.GetBackend(input["url"].Value, new Dictionary())) + b.Test(); + + OutputObject(bw, new { Status = "OK" }); + } + catch (Exception ex) + { + ReportError(response, bw, ex.Message); + } + } + private void ListSystemInfo(HttpServer.IHttpRequest request, HttpServer.IHttpResponse response, HttpServer.Sessions.IHttpSession session, BodyWriter bw) { OutputObject(bw, new @@ -329,7 +352,8 @@ namespace Duplicati.Server CompressionModules = Serializable.ServerSettings.CompressionModules, EncryptionModules = Serializable.ServerSettings.EncryptionModules, BackendModules = Serializable.ServerSettings.BackendModules, - GenericModules = Serializable.ServerSettings.GenericModules + GenericModules = Serializable.ServerSettings.GenericModules, + WebModules = Serializable.ServerSettings.WebModules }); } @@ -932,70 +956,92 @@ namespace Duplicati.Server HttpServer.HttpInput input = request.Method.ToUpper() == "POST" ? request.Form : request.QueryString; string command = input["command"].Value ?? ""; + string module = input["module"].Value ?? ""; long id; - - switch (command.ToLowerInvariant()) + + if (string.IsNullOrWhiteSpace(module)) { - case "pause": - if (input.Contains("duration") && !string.IsNullOrWhiteSpace(input["duration"].Value)) - { - TimeSpan ts; - try { ts = Library.Utility.Timeparser.ParseTimeSpan(input["duration"].Value); } - catch (Exception ex) + switch (command.ToLowerInvariant()) + { + case "pause": + if (input.Contains("duration") && !string.IsNullOrWhiteSpace(input["duration"].Value)) { - ReportError(response, bw, ex.Message); - return; + TimeSpan ts; + try + { + ts = Library.Utility.Timeparser.ParseTimeSpan(input["duration"].Value); + } + catch (Exception ex) + { + ReportError(response, bw, ex.Message); + return; + } + if (ts.TotalMilliseconds > 0) + Program.LiveControl.Pause(ts); + else + Program.LiveControl.Pause(); } - if (ts.TotalMilliseconds > 0) - Program.LiveControl.Pause(ts); else - Program.LiveControl.Pause(); - } - else - { - Program.LiveControl.Pause(); - } - - break; - case "resume": - Program.LiveControl.Resume(); - break; - - case "stop": - break; - - case "abort": - break; - - case "run": - case "run-backup": - { - Duplicati.Server.Serialization.Interface.IBackup backup = null; - if (long.TryParse(input["id"].Value, out id)) - backup = Program.DataConnection.GetBackup(id); - - if (backup == null) { - ReportError(response, bw, string.Format("No backup found for id: {0}", input["id"].Value)); - return; + Program.LiveControl.Pause(); } - - Program.WorkThread.AddTask(new Tuple(id, DuplicatiOperation.Backup)); - } - break; - case "clear-warning": - Program.HasWarning = false; - break; - case "clear-error": - Program.HasError = false; - break; + + break; + case "resume": + Program.LiveControl.Resume(); + break; + + case "stop": + break; + + case "abort": + break; + + case "run": + case "run-backup": + { + Duplicati.Server.Serialization.Interface.IBackup backup = null; + if (long.TryParse(input["id"].Value, out id)) + backup = Program.DataConnection.GetBackup(id); + + if (backup == null) + { + ReportError(response, bw, string.Format("No backup found for id: {0}", input["id"].Value)); + return; + } + + Program.WorkThread.AddTask(new Tuple(id, DuplicatiOperation.Backup)); + } + break; + case "clear-warning": + Program.HasWarning = false; + break; + case "clear-error": + Program.HasError = false; + break; + + default: + ReportError(response, bw, string.Format("Unsupported command {0}", command)); + return; + } - default: - ReportError(response, bw, string.Format("Unsupported command {0}", command)); - break; + OutputObject(bw, new { Status = "OK" }); + } + else + { + var m = Duplicati.Library.DynamicLoader.WebLoader.Modules.Where(x => x.Key.Equals(module, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); + if (m == null) + { + ReportError(response, bw, string.Format("Unsupported module {0}", command)); + return; + } + + OutputObject(bw, new { + Status = "OK", + Result = m.Execute(command.ToLowerInvariant(), input.ToDictionary(x => x.Name, x => x.Value)) + }); } - OutputObject(bw, new { Status = "OK" }); } } }