- add: packager

This commit is contained in:
2025-05-01 19:01:59 +03:00
parent 0ef326a970
commit 91c41302bb
18 changed files with 394 additions and 2 deletions

View File

@@ -0,0 +1,10 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Nebula.UpdateResolver.App"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.Styles>
<FluentTheme />
</Application.Styles>
</Application>

View File

@@ -0,0 +1,31 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Microsoft.Extensions.DependencyInjection;
using Nebula.Shared;
namespace Nebula.UpdateResolver;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
var services = new ServiceCollection();
services.AddServices();
services.AddTransient<MainWindow>();
var serviceProvider = services.BuildServiceProvider();
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = serviceProvider.GetService<MainWindow>();
}
base.OnFrameworkInitializationCompleted();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

@@ -0,0 +1,13 @@
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace Nebula.UpdateResolver;
public record struct LauncherManifest(
[property: JsonPropertyName("entries")] HashSet<LauncherManifestEntry> Entries
);
public record struct LauncherManifestEntry(
[property: JsonPropertyName("hash")] string Hash,
[property: JsonPropertyName("path")] string Path
);

View File

@@ -0,0 +1,40 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
ExtendClientAreaChromeHints="NoChrome"
ExtendClientAreaTitleBarHeightHint="-1"
ExtendClientAreaToDecorationsHint="True"
Height="225"
Width="400"
CanResize="False"
WindowStartupLocation="CenterScreen"
BorderThickness="0"
ShowInTaskbar="False"
mc:Ignorable="d" d:DesignWidth="400" d:DesignHeight="225"
x:Class="Nebula.UpdateResolver.MainWindow"
Title="Nebula.UpdateResolver">
<Grid ColumnDefinitions="*" RowDefinitions="*,40">
<Image Grid.Row="0" Source="Assets/back.gif" Grid.RowSpan="2"/>
<Border
BorderThickness="0,3,0,0"
CornerRadius="0"
Grid.Column="0"
Grid.Row="1">
<Border.Background>
<LinearGradientBrush EndPoint="50%,100%" StartPoint="50%,0%">
<GradientStop Color="#222222" Offset="0.0" />
<GradientStop Color="#222222" Offset="1.0" />
</LinearGradientBrush>
</Border.Background>
<Border.BorderBrush>
<LinearGradientBrush EndPoint="100%,50%" StartPoint="0%,50%">
<GradientStop Color="#222222" Offset="0.0" />
<GradientStop Color="#442222" Offset="1.0" />
</LinearGradientBrush>
</Border.BorderBrush>
<Label HorizontalAlignment="Center" VerticalAlignment="Center">Hello</Label>
</Border>
</Grid>
</Window>

View File

@@ -0,0 +1,82 @@
using System;
using System.Collections.Generic;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Controls;
using Nebula.Shared.FileApis.Interfaces;
using Nebula.Shared.Models;
using Nebula.Shared.Services;
namespace Nebula.UpdateResolver;
public partial class MainWindow : Window
{
private readonly ConfigurationService _configurationService;
private readonly RestService _restService;
private readonly HttpClient _httpClient = new HttpClient();
public IReadWriteFileApi FileApi { get; set; }
public MainWindow(FileService fileService, ConfigurationService configurationService, RestService restService)
{
_configurationService = configurationService;
_restService = restService;
InitializeComponent();
FileApi = fileService.CreateFileApi("app");
}
private async Task DownloadFiles()
{
var info = await EnsureFiles();
foreach (var file in info.ToDelete)
{
FileApi.Remove(file.Path);
}
foreach (var file in info.ToDownload)
{
using var response = _httpClient.GetAsync(
_configurationService.GetConfigValue(UpdateConVars.UpdateCacheUrl)
+ "/" + file.Hash
);
response.Result.EnsureSuccessStatusCode();
await using var stream = await response.Result.Content.ReadAsStreamAsync();
FileApi.Save(file.Path, stream);
}
}
private async Task<ManifestEnsureInfo> EnsureFiles()
{
var manifest = await _restService.GetAsync<LauncherManifest>(
_configurationService.GetConfigValue(UpdateConVars.UpdateCacheUrl)!, CancellationToken.None);
var toDownload = new HashSet<LauncherManifestEntry>();
var toDelete = new HashSet<LauncherManifestEntry>();
if (_configurationService.TryGetConfigValue(UpdateConVars.CurrentLauncherManifest, out var currentManifest))
{
foreach (var file in currentManifest.Entries)
{
if(!manifest.Entries.Contains(file))
toDelete.Add(file);
}
foreach (var file in manifest.Entries)
{
if(!currentManifest.Entries.Contains(file))
toDownload.Add(file);
}
}
else
{
_configurationService.SetConfigValue(UpdateConVars.CurrentLauncherManifest, manifest);
toDownload = manifest.Entries;
}
return new ManifestEnsureInfo(toDownload, toDelete);
}
}
public record struct ManifestEnsureInfo(HashSet<LauncherManifestEntry> ToDownload, HashSet<LauncherManifestEntry> ToDelete);

View File

@@ -0,0 +1,31 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<AvaloniaResource Include="Assets\**"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="11.2.1"/>
<PackageReference Include="Avalonia.Desktop" Version="11.2.1"/>
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.2.1"/>
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.2.1"/>
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<PackageReference Include="Avalonia.Diagnostics" Version="11.2.1">
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
</PackageReference>
<PackageReference Include="Microsoft.Extensions.DependencyInjection" Version="9.0.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Nebula.Shared\Nebula.Shared.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,21 @@
using Avalonia;
using System;
namespace Nebula.UpdateResolver;
class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.WithInterFont()
.LogToTrace();
}

View File

@@ -0,0 +1,13 @@
using System;
using Nebula.Shared.Models;
using Nebula.Shared.Services;
namespace Nebula.UpdateResolver;
public static class UpdateConVars
{
public static readonly ConVar<Uri> UpdateCacheUrl =
ConVarBuilder.Build<Uri>("update.url",new Uri("https://cinka.ru/nebula-launcher/files/publish/release"));
public static readonly ConVar<LauncherManifest> CurrentLauncherManifest =
ConVarBuilder.Build<LauncherManifest>("update.manifest");
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embedded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="Nebula.UpdateResolver.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>