- tweak: Change content hold think

This commit is contained in:
2025-03-13 14:58:47 +03:00
parent fecaa266cf
commit 5384e97640
12 changed files with 82 additions and 85 deletions

View File

@@ -197,12 +197,12 @@ public sealed partial class ContentBrowserViewModel : ViewModelBase , IViewModel
var rurl = serverUrl.ToRobustUrl(); var rurl = serverUrl.ToRobustUrl();
var info = await ContentService.GetBuildInfo(rurl, CancellationService.Token); var info = await ContentService.GetBuildInfo(rurl, CancellationService.Token);
var items = await ContentService.EnsureItems(info.RobustManifestInfo, loading, var hashApi = await ContentService.EnsureItems(info.RobustManifestInfo, loading,
CancellationService.Token); CancellationService.Token);
var rootEntry = new ContentEntry(this, "", "", serverUrl); var rootEntry = new ContentEntry(this, "", "", serverUrl);
foreach (var item in items) foreach (var item in hashApi.Manifest.Values)
{ {
var path = new ContentPath(item.Path); var path = new ContentPath(item.Path);
rootEntry.CreateItem(path, item); rootEntry.CreateItem(path, item);

View File

@@ -10,7 +10,7 @@ namespace Nebula.Launcher.ViewModels.Popup;
public sealed partial class ExceptionListViewModel : PopupViewModelBase public sealed partial class ExceptionListViewModel : PopupViewModelBase
{ {
[GenerateProperty] public override PopupMessageService PopupMessageService { get; } [GenerateProperty] public override PopupMessageService PopupMessageService { get; }
public override string Title => "Oopsie! Some shit is happened now!"; public override string Title => "Exception was thrown";
public override bool IsClosable => true; public override bool IsClosable => true;
public ObservableCollection<Exception> Errors { get; } = new(); public ObservableCollection<Exception> Errors { get; } = new();

View File

@@ -305,7 +305,7 @@ public partial class ServerEntryModelView : ViewModelBase
if (File.Exists(dotnetPath)) return dotnetPath; if (File.Exists(dotnetPath)) return dotnetPath;
} }
throw new Exception("Dotnet not found!"); return "dotnet";
} }
} }

View File

@@ -120,7 +120,7 @@
https://cinka.ru/nebula-launcher/ https://cinka.ru/nebula-launcher/
</TextBlock> </TextBlock>
</Button> </Button>
<TextBlock HorizontalAlignment="Right" VerticalAlignment="Center">v0.02-a</TextBlock> <TextBlock HorizontalAlignment="Right" VerticalAlignment="Center">v0.05-a</TextBlock>
</Panel> </Panel>
</Label> </Label>
</Border> </Border>

View File

@@ -7,7 +7,7 @@ using Robust.LoaderApi;
namespace Nebula.Runner; namespace Nebula.Runner;
[ServiceRegister] [ServiceRegister]
public sealed class App(DebugService debugService, RunnerService runnerService, ContentService contentService) public sealed class App(RunnerService runnerService, ContentService contentService)
: IRedialApi : IRedialApi
{ {
public void Redial(Uri uri, string text = "") public void Redial(Uri uri, string text = "")
@@ -16,8 +16,6 @@ public sealed class App(DebugService debugService, RunnerService runnerService,
public async Task Run(string[] args1) public async Task Run(string[] args1)
{ {
debugService.Log("HELLO!!! ");
var login = Environment.GetEnvironmentVariable("AUTH_LOGIN") ?? "Alexandra"; var login = Environment.GetEnvironmentVariable("AUTH_LOGIN") ?? "Alexandra";
var urlraw = Environment.GetEnvironmentVariable("GAME_URL") ?? "ss14://localhost"; var urlraw = Environment.GetEnvironmentVariable("GAME_URL") ?? "ss14://localhost";

View File

@@ -75,5 +75,5 @@ public sealed class FileApi : IReadWriteFileApi
return File.Exists(fullPath); return File.Exists(fullPath);
} }
public IEnumerable<string> AllFiles => Directory.EnumerateFiles(RootPath, "*.*", SearchOption.AllDirectories); public IEnumerable<string> AllFiles => Directory.EnumerateFiles(RootPath, "*.*", SearchOption.AllDirectories).Select(p=>p.Replace(RootPath,"").Substring(1));
} }

View File

@@ -1,4 +1,7 @@
using System.Diagnostics.CodeAnalysis; using System.Collections.Frozen;
using System.Collections.ObjectModel;
using System.Diagnostics.CodeAnalysis;
using Nebula.Shared.FileApis.Interfaces;
using Nebula.Shared.Models; using Nebula.Shared.Models;
using Robust.LoaderApi; using Robust.LoaderApi;
@@ -6,26 +9,59 @@ namespace Nebula.Shared.FileApis;
public class HashApi : IFileApi public class HashApi : IFileApi
{ {
private readonly IFileApi _fileApi; private readonly IReadWriteFileApi _fileApi;
public Dictionary<string, RobustManifestItem> Manifest; private readonly Dictionary<string, RobustManifestItem> _manifest;
public IReadOnlyDictionary<string, RobustManifestItem> Manifest => _manifest;
public HashApi(List<RobustManifestItem> manifest, IFileApi fileApi) public HashApi(List<RobustManifestItem> manifest, IReadWriteFileApi fileApi)
{ {
_fileApi = fileApi; _fileApi = fileApi;
Manifest = new Dictionary<string, RobustManifestItem>(); _manifest = new Dictionary<string, RobustManifestItem>();
foreach (var item in manifest) Manifest.TryAdd(item.Path, item); foreach (var item in manifest) _manifest.TryAdd(item.Path, item);
} }
public bool TryOpen(string path,[NotNullWhen(true)] out Stream? stream) public bool TryOpen(string path,[NotNullWhen(true)] out Stream? stream)
{ {
if (path[0] == '/') path = path.Substring(1); if (path[0] == '/') path = path.Substring(1);
if (Manifest.TryGetValue(path, out var a) && _fileApi.TryOpen(a.Hash, out stream)) if (_manifest.TryGetValue(path, out var a) && _fileApi.TryOpen(GetManifestPath(a), out stream))
return true; return true;
stream = null; stream = null;
return false; return false;
} }
public IEnumerable<string> AllFiles => Manifest.Keys; public bool TryOpen(RobustManifestItem item ,[NotNullWhen(true)] out Stream? stream){
if(_fileApi.TryOpen(GetManifestPath(item), out stream))
return true;
stream = null;
return false;
}
public bool TryOpenByHash(string hash ,[NotNullWhen(true)] out Stream? stream){
if(_fileApi.TryOpen(GetManifestPath(hash), out stream))
return true;
stream = null;
return false;
}
public bool Save(RobustManifestItem item, Stream stream){
return _fileApi.Save(GetManifestPath(item), stream);
}
public bool Has(RobustManifestItem item){
return _fileApi.Has(GetManifestPath(item));
}
private string GetManifestPath(RobustManifestItem item){
return GetManifestPath(item.Hash);
}
public static string GetManifestPath(string hash){
return hash[0].ToString() + hash[1].ToString() + '/' + hash;
}
public IEnumerable<string> AllFiles => _manifest.Keys;
} }

View File

@@ -4,7 +4,7 @@ public class LoginInfo
{ {
public Guid UserId { get; set; } public Guid UserId { get; set; }
public string Username { get; set; } = default!; public string Username { get; set; } = default!;
public LoginToken Token { get; set; } public LoginToken Token { get; set; } = default!;
public override string ToString() public override string ToString()
{ {

View File

@@ -2,7 +2,7 @@ namespace Nebula.Shared.Models;
public class RobustBuildInfo public class RobustBuildInfo
{ {
public ServerInfo BuildInfo; public ServerInfo BuildInfo = default!;
public RobustManifestInfo RobustManifestInfo; public RobustManifestInfo RobustManifestInfo;
public RobustUrl Url; public RobustUrl Url = default!;
} }

View File

@@ -2,6 +2,7 @@
using System.Globalization; using System.Globalization;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Numerics; using System.Numerics;
using Nebula.Shared.FileApis;
using Nebula.Shared.FileApis.Interfaces; using Nebula.Shared.FileApis.Interfaces;
using Nebula.Shared.Models; using Nebula.Shared.Models;
using Nebula.Shared.Utils; using Nebula.Shared.Utils;
@@ -15,7 +16,7 @@ public partial class ContentService
return fileService.ContentFileApi.Has(item.Hash); return fileService.ContentFileApi.Has(item.Hash);
} }
public async Task<List<RobustManifestItem>> EnsureItems(ManifestReader manifestReader, Uri downloadUri, public async Task<HashApi> EnsureItems(ManifestReader manifestReader, Uri downloadUri,
ILoadingHandler loadingHandler, ILoadingHandler loadingHandler,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
@@ -25,26 +26,22 @@ public partial class ContentService
while (manifestReader.TryReadItem(out var item)) while (manifestReader.TryReadItem(out var item))
{ {
if (cancellationToken.IsCancellationRequested) if (cancellationToken.IsCancellationRequested)
{ throw new TaskCanceledException();
debugService.Log("ensuring is cancelled!");
return [];
}
if (!CheckManifestExist(item.Value))
items.Add(item.Value);
allItems.Add(item.Value); allItems.Add(item.Value);
} }
var hashApi = new HashApi(allItems, fileService.ContentFileApi);
items = allItems.Where(a=> !hashApi.Has(a)).ToList();
debugService.Log("Download Count:" + items.Count); debugService.Log("Download Count:" + items.Count);
await Download(downloadUri, items, hashApi, loadingHandler, cancellationToken);
await Download(downloadUri, items, loadingHandler, cancellationToken); return hashApi;
fileService.ManifestItems = allItems;
return allItems;
} }
public async Task<List<RobustManifestItem>> EnsureItems(RobustManifestInfo info, ILoadingHandler loadingHandler, public async Task<HashApi> EnsureItems(RobustManifestInfo info, ILoadingHandler loadingHandler,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
debugService.Log("Getting manifest: " + info.Hash); debugService.Log("Getting manifest: " + info.Hash);
@@ -71,11 +68,12 @@ public partial class ContentService
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
debugService.Log("Unpack manifest files"); debugService.Log("Unpack manifest files");
var items = await EnsureItems(info, loadingHandler, cancellationToken); var hashApi = await EnsureItems(info, loadingHandler, cancellationToken);
var items = hashApi.Manifest.Values.ToList();
loadingHandler.AppendJob(items.Count); loadingHandler.AppendJob(items.Count);
foreach (var item in items) foreach (var item in items)
{ {
if (fileService.ContentFileApi.TryOpen(item.Hash, out var stream)) if (hashApi.TryOpen(item, out var stream))
{ {
debugService.Log($"Unpack {item.Hash} to: {item.Path}"); debugService.Log($"Unpack {item.Hash} to: {item.Path}");
otherApi.Save(item.Path, stream); otherApi.Save(item.Path, stream);
@@ -90,7 +88,7 @@ public partial class ContentService
} }
} }
public async Task Download(Uri contentCdn, List<RobustManifestItem> toDownload, ILoadingHandler loadingHandler, public async Task Download(Uri contentCdn, List<RobustManifestItem> toDownload, HashApi hashApi, ILoadingHandler loadingHandler,
CancellationToken cancellationToken) CancellationToken cancellationToken)
{ {
if (toDownload.Count == 0 || cancellationToken.IsCancellationRequested) if (toDownload.Count == 0 || cancellationToken.IsCancellationRequested)
@@ -189,10 +187,6 @@ public partial class ContentService
EnsureBuffer(ref readBuffer, length); EnsureBuffer(ref readBuffer, length);
var data = readBuffer.AsMemory(0, length); var data = readBuffer.AsMemory(0, length);
// Data to write to database.
var compression = ContentCompressionScheme.None;
var writeData = data;
if (preCompressed) if (preCompressed)
{ {
// Compressed length from extended header. // Compressed length from extended header.
@@ -210,10 +204,6 @@ public partial class ContentService
if (decompressedLength != data.Length) if (decompressedLength != data.Length)
throw new Exception($"Compressed blob {i} had incorrect decompressed size!"); throw new Exception($"Compressed blob {i} had incorrect decompressed size!");
// Set variables so that the database write down below uses them.
compression = ContentCompressionScheme.ZStd;
writeData = compressedData;
} }
else else
{ {
@@ -225,25 +215,8 @@ public partial class ContentService
await stream.ReadExactAsync(data, null); await stream.ReadExactAsync(data, null);
} }
if (!preCompressed)
{
// File wasn't pre-compressed. We should try to manually compress it to save space in DB.
EnsureBuffer(ref compressBuffer, ZStd.CompressBound(data.Length));
var compressLength = compressContext!.Compress(compressBuffer, data.Span);
// Don't bother saving compressed data if it didn't save enough space.
if (compressLength + 10 < length)
{
// Set variables so that the database write down below uses them.
compression = ContentCompressionScheme.ZStd;
writeData = compressBuffer.AsMemory(0, compressLength);
}
}
using var fileStream = new MemoryStream(data.ToArray()); using var fileStream = new MemoryStream(data.ToArray());
fileService.ContentFileApi.Save(item.Hash, fileStream); hashApi.Save(item, fileStream);
debugService.Log("file saved:" + item.Path); debugService.Log("file saved:" + item.Path);
loadingHandler.AppendResolvedJob(); loadingHandler.AppendResolvedJob();

View File

@@ -14,14 +14,11 @@ public class FileService
Environment.SpecialFolder.ApplicationData), "Datum"); Environment.SpecialFolder.ApplicationData), "Datum");
private readonly DebugService _debugService; private readonly DebugService _debugService;
public readonly IReadWriteFileApi ConfigurationApi;
public readonly IReadWriteFileApi ConfigurationApi;
public readonly IReadWriteFileApi ContentFileApi; public readonly IReadWriteFileApi ContentFileApi;
public readonly IReadWriteFileApi EngineFileApi; public readonly IReadWriteFileApi EngineFileApi;
public readonly IReadWriteFileApi ManifestFileApi; public readonly IReadWriteFileApi ManifestFileApi;
private HashApi? _hashApi;
public FileService(DebugService debugService) public FileService(DebugService debugService)
{ {
_debugService = debugService; _debugService = debugService;
@@ -29,21 +26,15 @@ public class FileService
EngineFileApi = CreateFileApi("engine"); EngineFileApi = CreateFileApi("engine");
ManifestFileApi = CreateFileApi("manifest"); ManifestFileApi = CreateFileApi("manifest");
ConfigurationApi = CreateFileApi("config"); ConfigurationApi = CreateFileApi("config");
}
public List<RobustManifestItem> ManifestItems // Some migrating think
{ foreach(var file in ContentFileApi.AllFiles){
set => _hashApi = new HashApi(value, ContentFileApi); if(file.Contains("\\") || !ContentFileApi.TryOpen(file, out var stream)) continue;
}
ContentFileApi.Save(HashApi.GetManifestPath(file), stream);
public HashApi HashApi stream.Dispose();
{ ContentFileApi.Remove(file);
get
{
if (_hashApi is null) throw new Exception("Hash API is not initialized!");
return _hashApi;
} }
set => _hashApi = value;
} }
public IReadWriteFileApi CreateFileApi(string path) public IReadWriteFileApi CreateFileApi(string path)

View File

@@ -8,7 +8,6 @@ public sealed class RunnerService(
ContentService contentService, ContentService contentService,
DebugService debugService, DebugService debugService,
ConfigurationService varService, ConfigurationService varService,
FileService fileService,
EngineService engineService, EngineService engineService,
AssemblyService assemblyService) AssemblyService assemblyService)
{ {
@@ -20,7 +19,7 @@ public sealed class RunnerService(
var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion); var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion);
if (engine is null) if (engine is null)
throw new Exception("Engine version is not usable: " + buildInfo.BuildInfo.Build.EngineVersion); throw new Exception("Engine version not found: " + buildInfo.BuildInfo.Build.EngineVersion);
await contentService.EnsureItems(buildInfo.RobustManifestInfo, loadingHandler, cancellationToken); await contentService.EnsureItems(buildInfo.RobustManifestInfo, loadingHandler, cancellationToken);
await engineService.EnsureEngineModules("Robust.Client.WebView", buildInfo.BuildInfo.Build.EngineVersion); await engineService.EnsureEngineModules("Robust.Client.WebView", buildInfo.BuildInfo.Build.EngineVersion);
@@ -35,13 +34,13 @@ public sealed class RunnerService(
var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion); var engine = await engineService.EnsureEngine(buildInfo.BuildInfo.Build.EngineVersion);
if (engine is null) if (engine is null)
throw new Exception("Engine version is not usable: " + buildInfo.BuildInfo.Build.EngineVersion); throw new Exception("Engine version not found: " + buildInfo.BuildInfo.Build.EngineVersion);
await contentService.EnsureItems(buildInfo.RobustManifestInfo, loadingHandler, cancellationToken); var hashApi = await contentService.EnsureItems(buildInfo.RobustManifestInfo, loadingHandler, cancellationToken);
var extraMounts = new List<ApiMount> var extraMounts = new List<ApiMount>
{ {
new(fileService.HashApi, "/") new(hashApi, "/")
}; };
var module = var module =