Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

TTS Download #230

Merged
merged 9 commits into from
Dec 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using UnitystationLauncher.Tests.MocksRepository.PingService;
using UnitystationLauncher.Tests.MocksRepository.ServerService;
using UnitystationLauncher.ViewModels;
using Xunit.Sdk;

namespace UnitystationLauncher.Tests.ViewModels;

Expand All @@ -16,7 +17,7 @@ public static void ServersPanelViewModel_ShouldFetchServers()
IPingService mockPingService = new MockPingStaticPingTime(5);
IServerService mockServerService = new MockRandomServers(1, 20);

ServersPanelViewModel serversPanelViewModel = new(mockInstallationService, mockPingService, mockServerService);
ServersPanelViewModel serversPanelViewModel = new(mockInstallationService, mockPingService, mockServerService, null, null);
serversPanelViewModel.ServerViews.Should().NotBeEmpty();
}

Expand All @@ -27,7 +28,7 @@ public static void ServersPanelViewModel_ShouldHandleExceptionInServerService()
IPingService mockPingService = new MockPingStaticPingTime(5);
IServerService mockServerService = new MockServersThrowsException();

Func<ServersPanelViewModel> act = () => new(mockInstallationService, mockPingService, mockServerService);
Func<ServersPanelViewModel> act = () => new(mockInstallationService, mockPingService, mockServerService, null, null);
act.Should().NotThrow();
act.Invoke().ServerViews.Should().NotBeNull().And.BeEmpty();
}
Expand Down
3 changes: 3 additions & 0 deletions UnitystationLauncher/Constants/ApiUrls.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ public static class ApiUrls

private static string RawGitHubFileBaseUrl => "https://raw.githubusercontent.com/unitystation/unitystation/develop";
public static string CodeScanListUrl => $"{RawGitHubFileBaseUrl}/CodeScanList.json";
public static string TTSFiles => $"{CdnBaseUrl}/STTBundleTTS/TTS";
public static string TTSVersionFile => $"{TTSFiles}/version.txt";

}
3 changes: 3 additions & 0 deletions UnitystationLauncher/Infrastructure/MessageBoxBuilder.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System.Collections.Generic;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using MsBox.Avalonia;
using MsBox.Avalonia.Base;
using MsBox.Avalonia.Dto;
Expand All @@ -14,6 +16,7 @@ public static IMsBox<string> CreateMessageBox(MessageBoxButtons buttonLayout, st
{
IMsBox<string> msgBox = MessageBoxManager.GetMessageBoxCustom(new MessageBoxCustomParams
{
Topmost = true,
SystemDecorations = Avalonia.Controls.SystemDecorations.BorderOnly,
WindowStartupLocation = Avalonia.Controls.WindowStartupLocation.CenterScreen,
ContentHeader = header,
Expand Down
2 changes: 1 addition & 1 deletion UnitystationLauncher/Models/Api/Server.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public Server(string forkName, int buildVersion, string serverIp, int serverPort
public string? OsxDownload { get; set; }
public string? LinuxDownload { get; set; }

public string ServerGoodFileVersion { get; set; } = string.Empty;
public string GoodFileVersion { get; set; } = string.Empty;

public (string, int) ForkAndVersion => (ForkName, BuildVersion);

Expand Down
9 changes: 9 additions & 0 deletions UnitystationLauncher/Models/Api/VersionModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using System.Text.Json.Serialization;

namespace UnitystationLauncher.Models.Api;

public class VersionModel
{
[JsonPropertyName("version")]
public required string Version { get; set; }
}
7 changes: 7 additions & 0 deletions UnitystationLauncher/Models/ConfigFile/Preferences.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class Preferences : ReactiveObject
private bool _autoRemove = true;
private int _ignoreVersionUpdate;
private string _installationPath = string.Empty;
private bool? _TTSEnabled = null;

public bool AutoRemove
{
Expand All @@ -25,4 +26,10 @@ public string InstallationPath
get => _installationPath;
set => this.RaiseAndSetIfChanged(ref _installationPath, value);
}

public bool? TTSEnabled
{
get => _TTSEnabled;
set => this.RaiseAndSetIfChanged(ref _TTSEnabled, value);
}
}
3 changes: 2 additions & 1 deletion UnitystationLauncher/Models/Enums/DownloadState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ public enum DownloadState
InProgress,
Scanning,
Installed,
Failed
Failed,
Extracting
}
10 changes: 5 additions & 5 deletions UnitystationLauncher/Services/CodeScanConfigService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,11 @@ public CodeScanConfigService(HttpClient httpClient, IPreferencesService preferen

string pathBase = _preferencesService.GetPreferences().InstallationPath;
string folderName = GetFolderName(version);
string versionPath = Path.Combine(pathBase, version, folderName);
string versionPath = Path.Combine(pathBase, "nonbuild", version, folderName);

if (Directory.Exists(versionPath) == false)
{
string zipExtractPath = Path.Combine(pathBase, version);
string zipExtractPath = Path.Combine(pathBase, "nonbuild", version);
HttpResponseMessage request = await _httpClient.GetAsync($"{ApiUrls.GoodFilesBaseUrl}/{version}/{folderName}.zip", HttpCompletionOption.ResponseHeadersRead);
await using Stream responseStream = await request.Content.ReadAsStreamAsync();
ZipArchive archive = new(responseStream);
Expand Down Expand Up @@ -183,12 +183,12 @@ private string GetZipFolderName()
switch (os)
{
case CurrentEnvironment.WindowsStandalone:
return "Windows";
return "StandaloneWindows64";
case CurrentEnvironment.LinuxFlatpak:
case CurrentEnvironment.LinuxStandalone:
return "Linux";
return "StandaloneLinux64";
case CurrentEnvironment.MacOsStandalone:
return "Mac";
return "StandaloneOSX";
default:
throw new UnsupportedPlatformException($"Unable to determine OS Version {os}");
}
Expand Down
6 changes: 4 additions & 2 deletions UnitystationLauncher/Services/CodeScanService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,10 @@ public async Task<bool> OnScanAsync(ZipArchive archive, string targetDirectory,
// TODO: Enable extraction cancelling
DirectoryInfo root = new(_preferencesService.GetPreferences().InstallationPath);

DirectoryInfo stagingDirectory = root.CreateSubdirectory("UnsafeBuildZipDirectory");
DirectoryInfo processingDirectory = root.CreateSubdirectory("UnsafeBuildProcessing");
var nonbuild = root.CreateSubdirectory("nonbuild");

DirectoryInfo stagingDirectory = nonbuild.CreateSubdirectory("UnsafeBuildZipDirectory");
DirectoryInfo processingDirectory = nonbuild.CreateSubdirectory("UnsafeBuildProcessing");
DirectoryInfo? dataPath = null;
archive.ExtractToDirectory(stagingDirectory.ToString(), true);
try
Expand Down
41 changes: 29 additions & 12 deletions UnitystationLauncher/Services/InstallationService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,17 +41,19 @@ public class InstallationService : IInstallationService
private readonly List<Download> _downloads;
private List<Installation> _installations = new();
private readonly string _installationsJsonFilePath;
private readonly ITTSService _TTSVersionService;

public InstallationService(HttpClient httpClient, IPreferencesService preferencesService,
IEnvironmentService environmentService, IServerService serverService, ICodeScanService codeScanService,
ICodeScanConfigService codeScanConfigService)
ICodeScanConfigService codeScanConfigService, ITTSService ITTSVersionService)
{
_httpClient = httpClient;
_preferencesService = preferencesService;
_environmentService = environmentService;
_serverService = serverService;
_codeScanService = codeScanService;
_codeScanConfigService = codeScanConfigService;
_TTSVersionService = ITTSVersionService;

_downloads = new();
_installationsJsonFilePath = Path.Combine(_environmentService.GetUserdataDirectory(), "installations.json");
Expand Down Expand Up @@ -93,14 +95,12 @@ public List<Installation> GetInstallations()
return (null!, failureReason);
}

server.ServerGoodFileVersion = "1.0.0"; //TODO

bool result = await _codeScanConfigService.ValidGoodFilesVersionAsync(server.ServerGoodFileVersion);
bool result = await _codeScanConfigService.ValidGoodFilesVersionAsync(server.GoodFileVersion);

if (result == false)
{
const string failureReason = "server does not have a valid ServerGoodFileVersion ";
Log.Warning(failureReason + $" ServerName: {server.ServerName} ServerGoodFileVersion : {server.ServerGoodFileVersion}");
Log.Warning(failureReason + $" ServerName: {server.ServerName} ServerGoodFileVersion : {server.GoodFileVersion}");
return (null!, failureReason);
}

Expand All @@ -115,9 +115,20 @@ public List<Installation> GetInstallations()

string installationBasePath = _preferencesService.GetPreferences().InstallationPath;
// should be something like {basePath}/{forkName}/{version}
string installationPath = Path.Combine(installationBasePath, server.ForkName.SanitiseStringPath(), server.ServerGoodFileVersion.SanitiseStringPath(), server.BuildVersion.ToString());
if (server.ForkName.SanitiseStringPath() == "nonbuild")
{
throw new Exception($" bad server ForkName {server.ForkName.SanitiseStringPath()} Not allowed as save location (nonbuild)");
}

if (server.ForkName.SanitiseStringPath() == "tts")
{
throw new Exception($" bad server ForkName {server.ForkName.SanitiseStringPath()} Not allowed as save location (tts) ");
}


download = new(downloadUrl, installationPath, server.ForkName, server.BuildVersion, server.ServerGoodFileVersion);
string installationPath = Path.Combine(installationBasePath, server.ForkName.SanitiseStringPath(), server.GoodFileVersion.SanitiseStringPath(), server.BuildVersion.ToString());

download = new(downloadUrl, installationPath, server.ForkName, server.BuildVersion, server.GoodFileVersion);

(bool canStartDownload, string cantDownloadReason) = CanStartDownload(download);

Expand All @@ -133,12 +144,17 @@ public List<Installation> GetInstallations()
}

_downloads.Add(download);



RxApp.MainThreadScheduler.ScheduleAsync((_, _) => StartDownloadAsync(download));
return (download, string.Empty);
}

public (bool, string) StartInstallation(Guid installationId, string? server = null, short? port = null)
{
_TTSVersionService.StartTTS();

Installation? installation = GetInstallationById(installationId);
if (installation == null)
{
Expand Down Expand Up @@ -422,6 +438,9 @@ private static string GetArguments(string? server, long? port)

private async Task StartDownloadAsync(Download download)
{
//Update TTS if it's needed
await _TTSVersionService.CheckAndDownloadLatestVersion(download);

Log.Information("Download requested, Installation Path '{Path}', Url '{Url}'", download.InstallPath, download.DownloadUrl);
try
{
Expand All @@ -433,13 +452,11 @@ private async Task StartDownloadAsync(Download download)
await using Stream responseStream = await request.Content.ReadAsStreamAsync();
Log.Information("Download connection established");
await using ProgressStream progressStream = new(responseStream);
download.Size = request.Content.Headers.ContentLength ??
throw new ContentLengthNullException(download.DownloadUrl);
download.Size = request.Content.Headers.ContentLength ?? throw new ContentLengthNullException(download.DownloadUrl);

using IDisposable logProgressDisposable = LogProgress(progressStream, download);

using IDisposable progressDisposable = progressStream.Progress
.Subscribe(p => { download.Downloaded = p; });
using IDisposable progressDisposable = progressStream.Progress.Subscribe(p => { download.Downloaded = p; });

// ExtractAndScan() must be run in a separate thread, but we want this one to wait for that one to finish
// Without this download progress will not work properly
Expand Down Expand Up @@ -558,7 +575,7 @@ private static async Task ShowScanFailPopUp(string message, string logFolder)
}
}

private static IDisposable LogProgress(ProgressStream progressStream, Download download)
public static IDisposable LogProgress(ProgressStream progressStream, Download download)
{
long lastPosition = 0L;
DateTime lastTime = DateTime.Now;
Expand Down
12 changes: 12 additions & 0 deletions UnitystationLauncher/Services/Interface/ITTSService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using System.Threading.Tasks;
using UnitystationLauncher.Models;

namespace UnitystationLauncher.Services.Interface;

public interface ITTSService
{
public Task CheckAndDownloadLatestVersion(Download Download);

public void StartTTS();
public void StopTTS();
}
Loading
Loading