mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-01-04 16:49:30 -06:00
195 lines
7.3 KiB
C#
195 lines
7.3 KiB
C#
using System.Net;
|
|
using HttpMethod = System.Net.Http.HttpMethod;
|
|
|
|
namespace FileFlows.Nextcloud.Helpers;
|
|
|
|
/// <summary>
|
|
/// Nextcloud uploader
|
|
/// </summary>
|
|
public interface INextcloudUploader
|
|
{
|
|
/// <summary>
|
|
/// Uploads a file to Nextcloud
|
|
/// </summary>
|
|
/// <param name="localFilePath">The full path to the file on disk to be uploaded.</param>
|
|
/// <param name="remoteFilePath">The path in Nextcloud where the file should be uploaded.</param>
|
|
/// <returns>True if the file was uploaded successfully; otherwise, false.</returns>
|
|
Result<bool> UploadFile(string localFilePath, string remoteFilePath);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Helper class for uploading files to Nextcloud
|
|
/// </summary>
|
|
/// <param name="logger">the Logger to use</param>
|
|
/// <param name="nextcloudUrl">The URL of the Nextcloud instance.</param>
|
|
/// <param name="username">The username for authentication.</param>
|
|
/// <param name="password">The password for authentication.</param>
|
|
public class NextcloudUploader(ILogger logger, string nextcloudUrl, string username, string password) : INextcloudUploader
|
|
{
|
|
private static HttpClient client;
|
|
|
|
static NextcloudUploader()
|
|
{
|
|
var handler = new HttpClientHandler
|
|
{
|
|
// Customize the handler as needed
|
|
ServerCertificateCustomValidationCallback =
|
|
(sender, cert, chain, sslPolicyErrors) => true // Ignore certificate errors
|
|
};
|
|
client = new HttpClient(handler);
|
|
}
|
|
|
|
|
|
/// <inheritdoc />
|
|
public Result<bool> UploadFile(string localFilePath, string remoteFilePath)
|
|
{
|
|
logger?.ILog("Uploading file: " + localFilePath);
|
|
try
|
|
{
|
|
string remoteFolder = remoteFilePath.Replace("\\", "/");
|
|
remoteFolder = string.Join("/", remoteFolder.Split("/")[..^1]);
|
|
logger?.ILog("Remote Folder: " + remoteFolder);
|
|
|
|
var fileStream = File.OpenRead(localFilePath);
|
|
|
|
int chunkIndex = 1;
|
|
int chunkSize = 80_000_000; // Split into chunks of approximately 80 MB
|
|
|
|
// Calculate the number of chunks based on the size of the compressed stream
|
|
long fileSize = fileStream.Length;
|
|
int numberOfChunks = (int)Math.Ceiling((double)fileSize / chunkSize);
|
|
|
|
fileStream.Position = 0; // Reset stream position
|
|
|
|
// Upload each chunk
|
|
while (fileStream.Position < fileSize)
|
|
{
|
|
int bytesToRead = (int)Math.Min(chunkSize, fileSize - fileStream.Position);
|
|
byte[] buffer = new byte[bytesToRead];
|
|
_ = fileStream.Read(buffer, 0, bytesToRead);
|
|
|
|
var chunkStream = new MemoryStream(buffer);
|
|
|
|
if (chunkIndex == 1)
|
|
CreateFolder(remoteFolder).Wait();
|
|
if (numberOfChunks == 1)
|
|
{
|
|
// Upload the chunk here using UploadFilePart method
|
|
UploadFilePart(chunkStream, remoteFilePath).Wait();
|
|
}
|
|
else
|
|
{
|
|
UploadFilePart(chunkStream, remoteFilePath).Wait();
|
|
}
|
|
|
|
chunkStream.Dispose();
|
|
|
|
chunkIndex++;
|
|
}
|
|
|
|
logger?.ILog("Upload completed with chunks: " + numberOfChunks);
|
|
return true; // All files uploaded successfully
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Result<bool>.Fail($"Error uploading file: {ex.Message}");
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Uploads a file to Nextcloud
|
|
/// </summary>
|
|
/// <param name="compressedStream">The stream to upload.</param>
|
|
/// <param name="remoteFilePath">The path in Nextcloud where the file should be uploaded.</param>
|
|
/// <returns>True if the file was uploaded successfully; otherwise, false.</returns>
|
|
private async Task<bool> UploadFilePart(MemoryStream compressedStream, string remoteFilePath)
|
|
{
|
|
logger?.ILog("Uploading file: " + remoteFilePath);
|
|
|
|
try
|
|
{
|
|
// Create the WebDAV request URL
|
|
string url = $"{nextcloudUrl.TrimEnd('/')}/remote.php/dav/files/{username}/{remoteFilePath.TrimStart('/')}";
|
|
|
|
// Set the credentials
|
|
var byteArray = new UTF8Encoding().GetBytes($"{username}:{password}");
|
|
client.DefaultRequestHeaders.Authorization =
|
|
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
|
|
|
|
// Set the content
|
|
compressedStream.Position = 0;
|
|
using (StreamContent content = new StreamContent(compressedStream))
|
|
{
|
|
content.Headers.ContentLength = compressedStream.Length;
|
|
|
|
// Send the PUT request
|
|
HttpResponseMessage response = await client.PutAsync(url, content);
|
|
|
|
// Check for success
|
|
if (response.StatusCode == HttpStatusCode.Created)
|
|
return true;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Handle any errors
|
|
logger?.ELog($"Error uploading file: {ex.Message}");
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Creates a folder on the WebDAV server at the specified path, ensuring all parent directories are created.
|
|
/// </summary>
|
|
/// <param name="remoteFolderPath">The path of the folder to be created on the server.</param>
|
|
/// <returns>True if the folder creation is successful, otherwise false.</returns>
|
|
private async Task<bool> CreateFolder(string remoteFolderPath)
|
|
{
|
|
logger?.ILog("Creating folder: " + remoteFolderPath);
|
|
|
|
try
|
|
{
|
|
// Create the WebDAV request URL
|
|
string baseUrl = $"{nextcloudUrl.TrimEnd('/')}/remote.php/dav/files/{username}";
|
|
|
|
// Split the remoteFolderPath into parts and create each folder sequentially
|
|
string[] folders = remoteFolderPath.Trim('/').Split('/');
|
|
string currentPath = string.Empty;
|
|
|
|
foreach (var folder in folders)
|
|
{
|
|
currentPath = string.IsNullOrEmpty(currentPath) ? folder : $"{currentPath}/{folder}";
|
|
string url = $"{baseUrl}/{currentPath}";
|
|
|
|
// Set the credentials
|
|
var byteArray = new UTF8Encoding().GetBytes($"{username}:{password}");
|
|
client.DefaultRequestHeaders.Authorization =
|
|
new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", Convert.ToBase64String(byteArray));
|
|
|
|
// Create the MKCOL request
|
|
HttpRequestMessage request = new HttpRequestMessage(new HttpMethod("MKCOL"), url);
|
|
|
|
// Send the request
|
|
HttpResponseMessage response = await client.SendAsync(request);
|
|
|
|
// Check for success, ignore if it already exists
|
|
if (response.StatusCode != HttpStatusCode.Created &&
|
|
response.StatusCode != HttpStatusCode.MethodNotAllowed)
|
|
{
|
|
logger?.ELog($"Failed to create folder: {currentPath}, Status: {response.StatusCode}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Handle any errors
|
|
logger?.ELog($"Error creating folder: {ex.Message}");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
} |