Skip to content

Commit

Permalink
#1833 add preflight
Browse files Browse the repository at this point in the history
  • Loading branch information
qdraw committed Dec 18, 2024
1 parent ff75bd1 commit 0ae4786
Show file tree
Hide file tree
Showing 10 changed files with 307 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ public class FfMpegDownload : IFfMpegDownload
private readonly FfmpegExePath _ffmpegExePath;
private readonly IStorage _hostFileSystemStorage;
private readonly IWebLogger _logger;
private readonly IFfMpegPreflightRunCheck _preflightRunCheck;
private readonly IFfMpegPrepareBeforeRunning _prepareBeforeRunning;

public FfMpegDownload(ISelectorStorage selectorStorage,
AppSettings appSettings,
IWebLogger logger, IFfMpegDownloadIndex downloadIndex,
IFfMpegDownloadBinaries downloadBinaries, IFfMpegPrepareBeforeRunning prepareBeforeRunning)
IFfMpegDownloadBinaries downloadBinaries, IFfMpegPrepareBeforeRunning prepareBeforeRunning,
IFfMpegPreflightRunCheck preflightRunCheck)
{
_appSettings = appSettings;
_hostFileSystemStorage =
Expand All @@ -33,6 +35,7 @@ public FfMpegDownload(ISelectorStorage selectorStorage,
_ffmpegExePath = new FfmpegExePath(_appSettings);
_downloadBinaries = downloadBinaries;
_prepareBeforeRunning = prepareBeforeRunning;
_preflightRunCheck = preflightRunCheck;
}

public async Task<FfmpegDownloadStatus> DownloadFfMpeg()
Expand Down Expand Up @@ -78,6 +81,11 @@ public async Task<FfmpegDownloadStatus> DownloadFfMpeg()
return FfmpegDownloadStatus.PrepareBeforeRunningFailed;
}

if ( !await _preflightRunCheck.TryRun(currentArchitecture) )
{
return FfmpegDownloadStatus.PreflightRunCheckFailed;
}

return FfmpegDownloadStatus.Ok;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,11 @@ protected override async Task ExecuteAsync(CancellationToken stoppingToken)
scope.ServiceProvider.GetRequiredService<IFfMpegDownloadBinaries>();
var prepareBeforeRunning =
scope.ServiceProvider.GetRequiredService<IFfMpegPrepareBeforeRunning>();
var preflightBeforeRunning =
scope.ServiceProvider.GetRequiredService<IFfMpegPreflightRunCheck>();

await new FfMpegDownload(selectorStorage, appSettings, logger, downloadIndex,
downloadBinaries, prepareBeforeRunning).DownloadFfMpeg();
var service = new FfMpegDownload(selectorStorage, appSettings, logger, downloadIndex,
downloadBinaries, prepareBeforeRunning, preflightBeforeRunning);
await service.DownloadFfMpeg();
}
}
15 changes: 15 additions & 0 deletions starsky/starsky.foundation.video/GetDependencies/FfMpegExePath.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using starsky.foundation.platform.Architecture;
using starsky.foundation.platform.Models;

namespace starsky.foundation.video.GetDependencies;
Expand All @@ -15,6 +16,20 @@ internal string GetExeParentFolder(string currentArchitecture)
: $"{FfmpegDependenciesFolder}-{currentArchitecture}");
}

/// <summary>
/// Get the path to the ffmpeg executable (assume current architecture)
/// </summary>
/// <returns>Full path of executable</returns>
internal string GetExePath()
{
return GetExePath(CurrentArchitecture
.GetCurrentRuntimeIdentifier());
}

/// <summary>
/// Get the path to the ffmpeg executable
/// </summary>
/// <returns>Full path of executable</returns>
internal string GetExePath(string currentArchitecture)
{
var exeFile = Path.Combine(GetExeParentFolder(currentArchitecture),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
using Medallion.Shell;
using starsky.foundation.injection;
using starsky.foundation.platform.Architecture;
using starsky.foundation.platform.Interfaces;
using starsky.foundation.platform.Models;
using starsky.foundation.video.GetDependencies.Interfaces;

namespace starsky.foundation.video.GetDependencies;

[Service(typeof(IFfMpegPreflightRunCheck), InjectionLifetime = InjectionLifetime.Scoped)]
public class FfMpegPreflightRunCheck(AppSettings appSettings, IWebLogger logger)
: IFfMpegPreflightRunCheck
{
public async Task<bool> TryRun()
{
var currentArchitecture = CurrentArchitecture.GetCurrentRuntimeIdentifier();
return await TryRun(currentArchitecture);
}

public async Task<bool> TryRun(string currentArchitecture)
{
var exePath = new FfmpegExePath(appSettings).GetExePath(currentArchitecture);

try
{
var result = await Command.Run(exePath, "-version").Task;

// Check if the command was successful
if ( result.Success )
{
var output = result.StandardOutput;
if ( output.Contains("ffmpeg", StringComparison.OrdinalIgnoreCase) )
{
return true;
}

logger.LogError($"[{nameof(FfMpegPreflightRunCheck)}] Invalid application");
}
else
{
logger.LogError($"[{nameof(FfMpegPreflightRunCheck)}] " +
$"Command failed with exit code " +
$"{result.ExitCode}: {result.StandardError}");
}

return false;
}
catch ( Exception exception )
{
logger.LogError($"[{nameof(FfMpegPreflightRunCheck)}] " +
$"An error occurred while checking FFMpeg: " +
$"{exception.Message}");

return false;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace starsky.foundation.video.GetDependencies.Interfaces;

public interface IFfMpegPreflightRunCheck
{
Task<bool> TryRun();
Task<bool> TryRun(string currentArchitecture);
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,6 @@ public enum FfmpegDownloadStatus
DownloadBinariesFailedMissingFileName,
DownloadBinariesFailedSha256Check,
DownloadBinariesFailedZipperNotExtracted,
PrepareBeforeRunningFailed
PrepareBeforeRunningFailed,
PreflightRunCheckFailed
}
37 changes: 37 additions & 0 deletions starsky/starskytest/FakeMocks/FakeIFfMpegPreflightRunCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
using System.Threading.Tasks;
using starsky.foundation.platform.Architecture;
using starsky.foundation.platform.Models;
using starsky.foundation.storage.Interfaces;
using starsky.foundation.video.GetDependencies;
using starsky.foundation.video.GetDependencies.Interfaces;

namespace starskytest.FakeMocks;

public class FakeIFfMpegPreflightRunCheck : IFfMpegPreflightRunCheck
{
private readonly AppSettings? _appSettings;
private readonly IStorage? _storage;

public FakeIFfMpegPreflightRunCheck(IStorage? storage = null, AppSettings? appSettings = null)
{
_storage = storage;
_appSettings = appSettings;
}

public async Task<bool> TryRun()
{
var currentArchitecture = CurrentArchitecture.GetCurrentRuntimeIdentifier();
return await TryRun(currentArchitecture);
}

public Task<bool> TryRun(string currentArchitecture)
{
if ( _appSettings == null || _storage == null )
{
return Task.FromResult(false);
}

var exePath = new FfmpegExePath(_appSettings).GetExePath(currentArchitecture);
return Task.FromResult(_storage.ExistFile(exePath));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public FfMpegDownloadBackgroundServiceTests()
services.AddSingleton<IFfMpegDownloadIndex, FakeIFfMpegDownloadIndex>();
services.AddSingleton<IFfMpegDownloadBinaries, FakeIFfMpegDownloadBinaries>();
services.AddSingleton<IFfMpegPrepareBeforeRunning, FakeIFfMpegPrepareBeforeRunning>();
services.AddSingleton<IFfMpegPreflightRunCheck, FakeIFfMpegPreflightRunCheck>();

var serviceProvider = services.BuildServiceProvider();
_serviceScopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ public async Task DownloadFfMpeg_ShouldSkipDueToSettings(string settingName)
var ffmpegDownload =
new FfMpegDownload(new FakeSelectorStorage(), appSettings,
logger, new FakeIFfMpegDownloadIndex(), new FakeIFfMpegDownloadBinaries(),
new FakeIFfMpegPrepareBeforeRunning());
new FakeIFfMpegPrepareBeforeRunning(), new FakeIFfMpegPreflightRunCheck());

var result = await ffmpegDownload.DownloadFfMpeg();

Expand All @@ -138,7 +138,7 @@ public async Task DownloadFfMpeg_MissingIndex()
new FfMpegDownload(new FakeSelectorStorage(), appSettings,
logger,
new FakeIFfMpegDownloadIndex(), new FakeIFfMpegDownloadBinaries(),
new FakeIFfMpegPrepareBeforeRunning());
new FakeIFfMpegPrepareBeforeRunning(), new FakeIFfMpegPreflightRunCheck());

var resultMissingIndex = await ffmpegDownload.DownloadFfMpeg();

Expand All @@ -158,7 +158,7 @@ public async Task DownloadFfMpeg_MissingIndex_DownloadBinariesFailedMissingFileN
new FakeIFfMpegDownloadIndex(new FfmpegBinariesContainer { Success = true }),
new FfMpegDownloadBinaries(new FakeSelectorStorage(_storage), _httpClientHelper,
appSettings, logger, new Zipper(new FakeIWebLogger())),
new FakeIFfMpegPrepareBeforeRunning());
new FakeIFfMpegPrepareBeforeRunning(), new FakeIFfMpegPreflightRunCheck());

var resultMissingIndex = await ffmpegDownload.DownloadFfMpeg();

Expand All @@ -180,7 +180,8 @@ public async Task DownloadFfMpeg_DownloadBinariesFail()
Data = new FfmpegBinariesIndex { Binaries = new List<BinaryIndex>() }
}),
new FakeIFfMpegDownloadBinaries(FfmpegDownloadStatus
.DownloadBinariesFailedMissingFileName), new FakeIFfMpegPrepareBeforeRunning());
.DownloadBinariesFailedMissingFileName), new FakeIFfMpegPrepareBeforeRunning(),
new FakeIFfMpegPreflightRunCheck());

var resultBinaryFail = await ffmpegDownload.DownloadFfMpeg();

Expand All @@ -207,7 +208,8 @@ public async Task DownloadFfMpeg_FileAlreadyExists()
{
Success = true,
Data = new FfmpegBinariesIndex { Binaries = new List<BinaryIndex>() }
}), new FakeIFfMpegDownloadBinaries(), new FakeIFfMpegPrepareBeforeRunning());
}), new FakeIFfMpegDownloadBinaries(), new FakeIFfMpegPrepareBeforeRunning(),
new FakeIFfMpegPreflightRunCheck());

var resultFileAlreadyExists = await ffmpegDownload.DownloadFfMpeg();

Expand All @@ -232,7 +234,7 @@ public async Task DownloadFfMpeg_DownloadFail_InvalidShaHash()
}),
new FfMpegDownloadBinaries(new FakeSelectorStorage(storage), _httpClientHelper,
appSettings, logger, new Zipper(new FakeIWebLogger())),
new FakeIFfMpegPrepareBeforeRunning());
new FakeIFfMpegPrepareBeforeRunning(), new FakeIFfMpegPreflightRunCheck());

var resultInvalidHash = await ffmpegDownload.DownloadFfMpeg();

Expand All @@ -258,7 +260,7 @@ public async Task DownloadFfMpeg_DownloadFail_ZipFileNotFound()
}),
new FfMpegDownloadBinaries(new FakeSelectorStorage(storage), _httpClientHelper,
appSettings, logger, new Zipper(new FakeIWebLogger())),
new FakeIFfMpegPrepareBeforeRunning());
new FakeIFfMpegPrepareBeforeRunning(), new FakeIFfMpegPreflightRunCheck());

var resultZipFail = await ffmpegDownload.DownloadFfMpeg();

Expand Down Expand Up @@ -295,7 +297,7 @@ public async Task DownloadFfMpeg_PrepareBeforeRunningFail()
new FfMpegPrepareBeforeRunning(new FakeSelectorStorage(storage),
new FakeIMacCodeSign(),
new FfMpegChmod(new FakeSelectorStorage(storage), logger), appSettings,
logger));
logger), new FakeIFfMpegPreflightRunCheck());

var resultPrepFail = await ffmpegDownload.DownloadFfMpeg();

Expand All @@ -308,6 +310,55 @@ public async Task DownloadFfMpeg_PrepareBeforeRunningFail()

Assert.AreEqual(FfmpegDownloadStatus.PrepareBeforeRunningFailed, resultPrepFail);
}

[TestMethod]
public async Task DownloadFfMpeg_PreflightRunCheckFailed()
{
var appSettings = new AppSettings { DependenciesFolder = DependencyFolderName };
var logger = new FakeIWebLogger();
var storage = new FakeIStorage(["/"],
new List<string>
{
$"FfMpegDownloadTest{Path.DirectorySeparatorChar}mock_test.zip", "/bin/chmod"
},
new List<byte[]?>
{
new CreateAnZipfileFakeFfMpeg().Bytes.ToArray(),
CreateAnZipFileMacOs.Bytes.ToArray()
});
var zipper = new FakeIZipper(new List<Tuple<string, byte[]>>
{
new($"FfMpegDownloadTest{Path.DirectorySeparatorChar}mock_test.zip",
[.. new CreateAnZipfileFakeFfMpeg().Bytes.ToArray()])
}, storage);

const string hash = "31852c0b33f35ff16e96d53be370ce86df92db6d4633ab0a8dae38acbf393ead";

var ffmpegDownload =
new FfMpegDownload(new FakeSelectorStorage(storage), appSettings,
logger,
new FakeIFfMpegDownloadIndex(new FfmpegBinariesContainer
{
Success = true,
Data = CreateExampleFile(hash),
BaseUrls = new List<Uri> { new("https://qdraw.nl/") }
}), new FfMpegDownloadBinaries(new FakeSelectorStorage(storage),
_httpClientHelper,
appSettings, logger, zipper), new FfMpegPrepareBeforeRunning(
new FakeSelectorStorage(storage),
new FakeIMacCodeSign(new Dictionary<string, bool?>
{
{
$"FfMpegDownloadTest/ffmpeg-{CurrentArchitecture.GetCurrentRuntimeIdentifier()}/ffmpeg",
true
}
}), new FakeIFfmpegChmod(storage), appSettings, logger),
new FfMpegPreflightRunCheck(appSettings, new FakeIWebLogger()));

var resultAllStages = await ffmpegDownload.DownloadFfMpeg();

Assert.AreEqual(FfmpegDownloadStatus.PreflightRunCheckFailed, resultAllStages);
}

[TestMethod]
public async Task DownloadFfMpeg_AllStages()
Expand Down Expand Up @@ -350,7 +401,8 @@ public async Task DownloadFfMpeg_AllStages()
$"FfMpegDownloadTest/ffmpeg-{CurrentArchitecture.GetCurrentRuntimeIdentifier()}/ffmpeg",
true
}
}), new FakeIFfmpegChmod(storage), appSettings, logger));
}), new FakeIFfmpegChmod(storage), appSettings, logger),
new FakeIFfMpegPreflightRunCheck(storage, appSettings));

var resultAllStages = await ffmpegDownload.DownloadFfMpeg();

Expand Down
Loading

0 comments on commit 0ae4786

Please sign in to comment.