diff --git a/Backup2Cloud/Args/ExampleOptions.cs b/Backup2Cloud/Args/ExampleOptions.cs
index 53e5c1c..5d29157 100644
--- a/Backup2Cloud/Args/ExampleOptions.cs
+++ b/Backup2Cloud/Args/ExampleOptions.cs
@@ -7,5 +7,16 @@ public class ExampleOptions
{
[Option('s', "save", Required = false, Default = null, HelpText = "示例配置文件保存地址。")]
public string Path { get; set; }
+
+ [Option('l', "list", Required = false, Default = null, HelpText = "获取datasource或uploader的名称。可以为 datasource 或 uploader")]
+
+ public string List { get; set; }
+
+ [Option('d', "datasource", Required = false, Default = null, HelpText = "获取datasource的格式,需填写名称。")]
+ public string DataSource { get; set; }
+
+
+ [Option('u', "uploader", Required = false, Default = null, HelpText = "获取uploader的格式,需填写名称。")]
+ public string Uploader { get; set; }
}
}
diff --git a/Backup2Cloud/Backup2Cloud.csproj b/Backup2Cloud/Backup2Cloud.csproj
index 7458417..c16a27c 100644
--- a/Backup2Cloud/Backup2Cloud.csproj
+++ b/Backup2Cloud/Backup2Cloud.csproj
@@ -19,18 +19,23 @@
-
+
-
+
+
-
+
-
+
-
+
+
+
+
+
diff --git a/Backup2Cloud/Conf/BaseFtpConf.cs b/Backup2Cloud/Conf/BaseFtpConf.cs
new file mode 100644
index 0000000..f1224a7
--- /dev/null
+++ b/Backup2Cloud/Conf/BaseFtpConf.cs
@@ -0,0 +1,46 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Backup2Cloud.Conf
+{
+ ///
+ /// FTP基本配置。
+ ///
+ public abstract class BaseFtpConf
+ {
+ ///
+ /// 服务器主机名。
+ /// 默认为本机。
+ ///
+ public string host { get; set; } = "localhost";
+
+ ///
+ /// 服务器的FTP端口。
+ /// 默认为21。
+ ///
+ public int port { get; set; } = 21;
+
+ ///
+ /// 用户名。
+ /// 默认为anonymous。
+ ///
+ public string user { get; set; } = "anonymous";
+
+ ///
+ /// 密码。
+ ///
+ public string password { get; set; } = string.Empty;
+
+ ///
+ /// 是否使用匿名登陆。
+ /// 默认为false。
+ ///
+ public bool anonymous { get; set; } = false;
+
+ ///
+ /// 在ftp上的路径。
+ ///
+ public string path { get; set; } = "/";
+ }
+}
diff --git a/Backup2Cloud/Conf/ExamplePrinter.cs b/Backup2Cloud/Conf/ExamplePrinter.cs
index 782fd23..2353489 100644
--- a/Backup2Cloud/Conf/ExamplePrinter.cs
+++ b/Backup2Cloud/Conf/ExamplePrinter.cs
@@ -1,4 +1,5 @@
using Backup2Cloud.Args;
+using Backup2Cloud.DataSource;
using Backup2Cloud.Logging;
using Backup2Cloud.Uploader;
using Newtonsoft.Json;
@@ -21,38 +22,103 @@ public class ExamplePrinter
public static void Print(ExampleOptions options)
{
var uploaders = NamedInterfaceLoader.Load(typeof(IUploader));
- List configurations = new List();
- string[] crontab = { "0,30 * * * * ?" };
- foreach (var i in uploaders)
+ var dataSources = NamedInterfaceLoader.Load(typeof(IDataSource));
+ string content = string.Empty;
+ if (string.IsNullOrEmpty(options.List) == false)
{
- SingleConfiguration single = new SingleConfiguration()
+ if (options.List == "datasource")
{
- uploader = (Activator.CreateInstance(i.Value) as IUploader).GetExample() as IUploader,
- name = "上传到 " + i.Key,
- path = "/data",
- crontab = new HashSet(crontab)
- };
-
- configurations.Add(single);
+ content = string.Join('\n', dataSources.Keys);
+ Console.WriteLine("已支持以下数据源:");
+ }
+ else if (options.List == "uploader")
+ {
+ content = string.Join('\n', uploaders.Keys);
+ Console.WriteLine("已支持以下上传类:");
+ }
+ else
+ {
+ Console.WriteLine("只能列出 datasource 或 uploader");
+ }
}
-
- string json = JsonConvert.SerializeObject(configurations, Formatting.Indented, new NameConverter());
- Log.Info("\n\n示例文件:\n");
- Console.WriteLine(json);
- if (string.IsNullOrEmpty(options.Path) == false)
+ else if (string.IsNullOrEmpty(options.Uploader) == false)
{
- //保存到文件。
- using (StreamWriter stream = new StreamWriter(options.Path, false, Encoding.UTF8))
+ if (uploaders.ContainsKey(options.Uploader))
{
- stream.Write(json);
+ content = JsonConvert.SerializeObject((Activator.CreateInstance(uploaders[options.Uploader]) as IExampled).GetExample(),
+ Formatting.Indented,
+ new NameConverter());
}
+ else
+ {
+ Console.WriteLine($"不存在uploader类: { options.Uploader }");
+ }
+ }
+ else if (string.IsNullOrEmpty(options.DataSource) == false)
+ {
+ if (dataSources.ContainsKey(options.DataSource))
+ {
+ content = JsonConvert.SerializeObject((Activator.CreateInstance(dataSources[options.DataSource]) as IExampled).GetExample(),
+ Formatting.Indented,
+ new NameConverter());
+ }
+ else
+ {
+ Console.WriteLine($"不存在datasource类: { options.DataSource }");
+ }
+ }
+ else
+ {
+ content = GetExampleConfig(uploaders, dataSources);
+ }
- Log.Info(string.Format("示例文件已经保存到\"{0}\"。", options.Path));
+ if (string.IsNullOrEmpty(content) == false)
+ {
+ Console.WriteLine(content);
+ if (string.IsNullOrEmpty(options.Path) == false)
+ {
+ //保存到文件。
+ using (StreamWriter stream = new StreamWriter(options.Path, false, Encoding.UTF8))
+ {
+ stream.Write(content);
+ }
+
+ Console.WriteLine("\n\n");
+ Log.Info(string.Format("文件已经保存到\"{0}\"。", options.Path));
+ }
}
#if !DEBUG
Environment.Exit(0);
#endif
}
+
+ private static string GetExampleConfig(Dictionary uploaders, Dictionary dataSources)
+ {
+ string[] crontab = { "0,30 * * * * ?" };
+ List configurations = new List();
+ SingleConfiguration single = new SingleConfiguration()
+ {
+ name = "上传到 ",
+ path = "/data",
+ crontab = new HashSet(crontab)
+ };
+
+ if (uploaders.Count > 0)
+ {
+ var i = uploaders.GetEnumerator().Current;
+ single.uploader = (Activator.CreateInstance(i.Value) as IUploader).GetExample() as IUploader;
+ single.name += i.Key;
+ }
+
+ if (dataSources.Count > 0)
+ {
+ var i = dataSources.GetEnumerator().Current;
+ single.dataSource = (Activator.CreateInstance(i.Value) as IDataSource).GetExample() as IDataSource;
+ }
+
+ configurations.Add(single);
+ return JsonConvert.SerializeObject(configurations, Formatting.Indented, new NameConverter());
+ }
}
}
diff --git a/Backup2Cloud/Conf/SingleConfiguration.cs b/Backup2Cloud/Conf/SingleConfiguration.cs
index a7d6c11..0d4094c 100644
--- a/Backup2Cloud/Conf/SingleConfiguration.cs
+++ b/Backup2Cloud/Conf/SingleConfiguration.cs
@@ -7,7 +7,7 @@ namespace Backup2Cloud.Conf
///
/// 单条备份配置
///
- public struct SingleConfiguration : IConfigurable
+ public class SingleConfiguration : IConfigurable
{
///
/// 任务名称
diff --git a/Backup2Cloud/DataSource/FtpDataSource.cs b/Backup2Cloud/DataSource/FtpDataSource.cs
new file mode 100644
index 0000000..45d93b7
--- /dev/null
+++ b/Backup2Cloud/DataSource/FtpDataSource.cs
@@ -0,0 +1,117 @@
+using Backup2Cloud.Conf;
+using Backup2Cloud.Logging;
+using FluentFTP;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+
+namespace Backup2Cloud.DataSource
+{
+ ///
+ /// FTP数据源。从远端FTP获取数据。
+ ///
+ [Name("ftp")]
+ public class FtpDataSource : BaseFtpConf, IDataSource
+ {
+ public string Tips
+ {
+ get
+ {
+ return string.Empty;
+ }
+ }
+
+ public object GetExample()
+ {
+ return new FtpDataSource();
+ }
+
+ public void SaveData(string des)
+ {
+ using (FtpClient client = new FtpClient(host))
+ {
+ client.Port = port;
+ client.Encoding = Encoding.UTF8;
+ if (anonymous == false)
+ {
+ client.Credentials = new NetworkCredential(user, password);
+ }
+
+ client.Connect();
+ if (client.DirectoryExists(path))
+ {
+ int result = DownloadDirectory(path, "/", des, client);
+ Log.Print($"从 ftp://{ host }:{ port }{ path } 成功下载 { result } 个文件到 { des } 。");
+ }
+ else
+ {
+ if (client.DownloadFile(des, path) == false)
+ {
+ throw new IOException($"下载 ftp://{ host }:{ port }{ path } 失败。");
+ }
+
+ Log.Print($"成功下载 ftp://{ host }:{ port }{ path } 到 { des } 。");
+ }
+
+ client.Disconnect();
+ }
+ }
+
+ private int DownloadDirectory(string baseSrc, string dir, string des, FtpClient client)
+ {
+ string target = FormatDirectoryName(des + dir);
+ if (Directory.Exists(target))
+ {
+ Directory.Delete(target, true);
+ }
+
+ Directory.CreateDirectory(target);
+ var list = client.GetListing(FormatDirectoryName(baseSrc + dir));
+ List dirs = new List();
+ int result = 0;
+ foreach (var i in list)
+ {
+ switch (i.Type)
+ {
+ case FtpFileSystemObjectType.File:
+ if (client.DownloadFile(target + i.Name, i.FullName))
+ {
+ ++result;
+ }
+
+ break;
+
+ case FtpFileSystemObjectType.Directory:
+ dirs.Add(i.Name);
+ break;
+
+ case FtpFileSystemObjectType.Link:
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ foreach (var i in dirs)
+ {
+ result += DownloadDirectory(baseSrc, dir + i + "/", des + i + "/", client);
+ }
+
+ return result;
+ }
+
+ private string FormatDirectoryName(string name)
+ {
+ name = name.Replace("\\", "/");
+ name = name.Replace("//", "/");
+ if (name.EndsWith("/") == false)
+ {
+ name += "/";
+ }
+
+ return name;
+ }
+ }
+}
diff --git a/Backup2Cloud/Uploader/FtpUploader.cs b/Backup2Cloud/Uploader/FtpUploader.cs
new file mode 100644
index 0000000..67cbdc4
--- /dev/null
+++ b/Backup2Cloud/Uploader/FtpUploader.cs
@@ -0,0 +1,50 @@
+using Backup2Cloud.Conf;
+using FluentFTP;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Backup2Cloud.Uploader
+{
+ public class FtpUploader : BaseFtpConf, IUploader
+ {
+ public string Tips
+ {
+ get
+ {
+ return string.Empty;
+ }
+ }
+
+ public object GetExample()
+ {
+ return new FtpUploader();
+ }
+
+ public Task Upload(string file, string suffix)
+ {
+ using (FtpClient client = new FtpClient(host))
+ {
+ client.Port = port;
+ client.Encoding = Encoding.UTF8;
+ if (anonymous == false)
+ {
+ client.Credentials = new NetworkCredential(user, password);
+ }
+
+ client.Connect();
+ if (client.UploadFile(file, path + suffix) == false)
+ {
+ throw new IOException($"上传 ftp://{ host }:{ port }{ path }{ suffix } 失败。");
+ }
+
+ client.Disconnect();
+ }
+
+ return Task.CompletedTask;
+ }
+ }
+}