diff --git a/Nebula.Shared/FileApis/FtpFileApi.cs b/Nebula.Shared/FileApis/FtpFileApi.cs
new file mode 100644
index 0000000..43d7103
--- /dev/null
+++ b/Nebula.Shared/FileApis/FtpFileApi.cs
@@ -0,0 +1,74 @@
+using System.Net;
+using FluentFTP;
+using Nebula.Shared.FileApis.Interfaces;
+
+namespace Nebula.Shared.FileApis;
+
+public class FtpFileApi : IWriteFileApi, IDisposable
+{
+ private readonly string _ftpHost;
+ private readonly string _username;
+ private readonly string _password;
+
+ private readonly FtpClient Client;
+
+ public FtpFileApi(string ftpHost, string username, string password)
+ {
+ _ftpHost = ftpHost;
+ _username = username;
+ _password = password;
+ Client = CreateClient();
+ Client.AutoConnect();
+ }
+
+ public bool Save(string path, Stream input)
+ {
+ try
+ {
+ var result = Client.UploadStream(input, path, FtpRemoteExists.Overwrite, true);
+ return result == FtpStatus.Success;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ public bool Remove(string path)
+ {
+ try
+ {
+ Client.DeleteFile(path);
+ return true;
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ public bool Has(string path)
+ {
+ try
+ {
+ return Client.FileExists(path);
+ }
+ catch
+ {
+ return false;
+ }
+ }
+
+ private FtpClient CreateClient()
+ {
+ var client = new FtpClient(_ftpHost, _username, _password);
+ client.Config.EncryptionMode = FtpEncryptionMode.None;
+ client.Config.ValidateAnyCertificate = true;
+ return client;
+ }
+
+ public void Dispose()
+ {
+ Client.Dispose();
+ }
+}
\ No newline at end of file
diff --git a/Nebula.Shared/Nebula.Shared.csproj b/Nebula.Shared/Nebula.Shared.csproj
index d255146..51c89f5 100644
--- a/Nebula.Shared/Nebula.Shared.csproj
+++ b/Nebula.Shared/Nebula.Shared.csproj
@@ -11,14 +11,15 @@
Utility.runtime.json
-
-
-
+
+
+
+
-
-
+
+
diff --git a/Nebula.Shared/Services/ContentService.Download.cs b/Nebula.Shared/Services/ContentService.Download.cs
index 472dc8e..41372a6 100644
--- a/Nebula.Shared/Services/ContentService.Download.cs
+++ b/Nebula.Shared/Services/ContentService.Download.cs
@@ -69,12 +69,18 @@ public partial class ContentService
debugService.Log("Unpack manifest files");
var items = hashApi.Manifest.Values.ToList();
loadingHandler.AppendJob(items.Count);
- foreach (var item in items)
+
+ var options = new ParallelOptions
+ {
+ MaxDegreeOfParallelism = 10
+ };
+
+ Parallel.ForEach(items, options, item =>
{
if (hashApi.TryOpen(item, out var stream))
{
debugService.Log($"Unpack {item.Hash} to: {item.Path}");
- otherApi.Save(item.Path, stream);
+ otherApi.Save(item.Hash, stream);
stream.Close();
}
else
@@ -83,7 +89,9 @@ public partial class ContentService
}
loadingHandler.AppendResolvedJob();
- }
+ });
+
+
if (loadingHandler is IDisposable disposable)
{
diff --git a/Nebula.sln.DotSettings.user b/Nebula.sln.DotSettings.user
new file mode 100644
index 0000000..cd39add
--- /dev/null
+++ b/Nebula.sln.DotSettings.user
@@ -0,0 +1,2 @@
+
+ ForceIncluded
\ No newline at end of file