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" });
}
}
}