aboutsummaryrefslogtreecommitdiff
path: root/src/Publishing/FtpUploadManager.cs
blob: a955bb8eb2c2583a8bc00266309ef65c77ed7ffe (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
using System;
using System.IO;

using FluentFTP;

using System.Diagnostics.CodeAnalysis;
using System.Threading.Tasks;

using VNLib.Tools.Build.Executor.Model;
using VNLib.Tools.Build.Executor.Constants;

namespace VNLib.Tools.Build.Executor.Publishing
{
    internal sealed class FtpUploadManager(AsyncFtpClient client, string remotePath) : IUploadManager
    {
        public async Task UploadDirectoryAsync(string path)
        {
            path = Directory.GetParent(path)!.FullName;

            await client.AutoConnect();

            var res = await client.UploadDirectory(
                localFolder: path,
                remoteFolder: remotePath,
                FtpFolderSyncMode.Update,
                FtpRemoteExists.Overwrite,
                FtpVerify.Throw | FtpVerify.Retry
            );

            foreach(FtpResult fileResult in res)
            {
                switch (fileResult.ToStatus())
                {
                    case FtpStatus.Success:
                        Config.Log.Information(
                            "Uploaded {size} bytes, {0} -> {1}",
                            fileResult.Size, 
                            fileResult.LocalPath, 
                            fileResult.RemotePath
                        );
                        break;

                    case FtpStatus.Skipped:
                        Config.Log.Information("Skipped {0} -> {1}", fileResult.LocalPath, fileResult.RemotePath);
                        break;

                    case FtpStatus.Failed:
                        Config.Log.Warning(
                            "Failed to upload {0}, reason: {exp}", 
                            fileResult.LocalPath, 
                            fileResult.Exception?.Message
                        );
                        break;  
                }
            }
        }

        [return: NotNullIfNotNull(nameof(serverAddress))]
        public static IUploadManager? Create(string? serverAddress)
        {
            if(string.IsNullOrWhiteSpace(serverAddress))
            {
                return null;
            }

            //Convert to uri, this may throw but this is currently the best way to validate the address
            Uri serverUri = new(serverAddress);

            //Initlaize the client
            AsyncFtpClient client = new()
            {
                Host = serverUri.Host,
                Port = serverUri.Port,
                

                Config = new()
                {
                    LogToConsole = Config.Log.IsEnabled(Serilog.Events.LogEventLevel.Verbose),

                    //Disable senstive logging in case running in automated CI pipelines where logs may be published
                    LogUserName = false,
                    LogPassword = false,
                    //EncryptionMode = FtpEncryptionMode.Auto,
                    RetryAttempts = 3,
                },

                Credentials = new()
                {
                    //Pull credentials from the environment instead of command line
                    UserName = Environment.GetEnvironmentVariable("FTP_USERNAME"),
                    Password = Environment.GetEnvironmentVariable("FTP_PASSWORD")
                },
            };

            return new FtpUploadManager(client, serverUri.LocalPath);
        }
    }
}