EllieHub 1.0.3.0
This commit is contained in:
commit
9180716702
8 changed files with 76 additions and 47 deletions
|
@ -8,7 +8,6 @@
|
|||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<WarningsAsErrors>Nullable</WarningsAsErrors>
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
<EnforceCodeStyleInBuild>True</EnforceCodeStyleInBuild>
|
||||
<GenerateDocumentationFile>True</GenerateDocumentationFile>
|
||||
<BuiltInComInteropSupport>True</BuiltInComInteropSupport>
|
||||
|
@ -16,11 +15,12 @@
|
|||
|
||||
<!--Publishing-->
|
||||
<PublishSingleFile>true</PublishSingleFile>
|
||||
<EnableCompressionInSingleFile>true</EnableCompressionInSingleFile>
|
||||
<SelfContained>true</SelfContained>
|
||||
<DebugType>embedded</DebugType>
|
||||
|
||||
<!--Version-->
|
||||
<VersionPrefix>1.0.2.0</VersionPrefix>
|
||||
<VersionPrefix>1.0.3.0</VersionPrefix>
|
||||
|
||||
<!--Avalonia Settings-->
|
||||
<ApplicationManifest>app.manifest</ApplicationManifest>
|
||||
|
@ -30,6 +30,13 @@
|
|||
<UseAppHost>true</UseAppHost>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<TreatWarningsAsErrors>False</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<TreatWarningsAsErrors>True</TreatWarningsAsErrors>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<AvaloniaResource Include="Assets\**" />
|
||||
|
||||
|
|
|
@ -83,8 +83,8 @@ public static class WindowExt
|
|||
{
|
||||
return (!activeView.TryFindResource(resourceName, theme, out var resource))
|
||||
? throw new InvalidOperationException($"Resource '{resourceName}' was not found.")
|
||||
: (!Utilities.TryCastTo<T>(resource, out var result))
|
||||
? throw new InvalidCastException($"Could not convert resource of type '{resource?.GetType()?.FullName}' to '{nameof(T)}'.")
|
||||
: result;
|
||||
: (resource is T castResource)
|
||||
? castResource
|
||||
: throw new InvalidCastException($"Could not convert resource of type '{resource?.GetType()?.FullName}' to '{nameof(T)}'.");
|
||||
}
|
||||
}
|
|
@ -20,7 +20,7 @@ namespace EllieHub.Features.AppConfig.ViewModels;
|
|||
/// </summary>
|
||||
public class ConfigViewModel : ViewModelBase<ConfigView>
|
||||
{
|
||||
private static readonly string _unixNotice = Environment.OSVersion.Platform is not PlatformID.Unix
|
||||
private static readonly string _unixNotice = (Environment.OSVersion.Platform is not PlatformID.Unix)
|
||||
? string.Empty
|
||||
: Environment.NewLine + "To make the dependencies accessible to your bot instances without this updater, consider installing " +
|
||||
$"them through your package manager or adding the directory \"{AppStatics.AppDepsUri}\" to your PATH environment variable.";
|
||||
|
|
|
@ -69,10 +69,10 @@ public partial class LateralBarView : ReactiveUserControl<LateralBarViewModel>
|
|||
/// <exception cref="InvalidOperationException">Occurs when the visual tree has an unexpected structure.</exception>
|
||||
public void ApplyBotButtonBorder(Button button)
|
||||
{
|
||||
if (!Utilities.TryCastTo<Border>(button.Parent?.Parent, out var border))
|
||||
if (button.Parent?.Parent is not Border border)
|
||||
throw new InvalidOperationException("Visual tree has an unexpected structure.");
|
||||
|
||||
if (!Utilities.TryCastTo<ImmutableSolidColorBrush>(this.FindResource(base.ActualThemeVariant, "BotSelectionColor"), out var resourceColor))
|
||||
if (this.FindResource(base.ActualThemeVariant, "BotSelectionColor") is not ImmutableSolidColorBrush resourceColor)
|
||||
return;
|
||||
|
||||
border.BorderBrush = resourceColor;
|
||||
|
@ -95,7 +95,7 @@ public partial class LateralBarView : ReactiveUserControl<LateralBarViewModel>
|
|||
private void LoadBotViewModel(object sender, RoutedEventArgs eventArgs)
|
||||
{
|
||||
// "sender", for some reason, is not one of the buttons stored in the lateral bar's view-model.
|
||||
if (Utilities.TryCastTo<Button>(sender, out var button) && this.ViewModel!.BotButtonList.First(x => x.Content == button.Content).IsEnabled)
|
||||
if (sender is Button button && this.ViewModel!.BotButtonList.First(x => x.Content == button.Content).IsEnabled)
|
||||
BotButtonClick?.Invoke(button, eventArgs);
|
||||
}
|
||||
|
||||
|
@ -108,10 +108,11 @@ public partial class LateralBarView : ReactiveUserControl<LateralBarViewModel>
|
|||
/// <exception cref="InvalidOperationException">Occurs when the visual tree has an unexpected structure.</exception>
|
||||
private void OnBotButtonLoad(object? sender, VisualTreeAttachmentEventArgs eventArgs)
|
||||
{
|
||||
if (!Utilities.TryCastTo<Panel>(sender, out var panel)
|
||||
|| !Utilities.TryCastTo<SKImageView>(((Border)panel.Children[0]).Child, out var botAvatar)
|
||||
|| !Utilities.TryCastTo<Button>(panel.Children[1], out var button)
|
||||
|| !Utilities.TryCastTo<Guid>(button.Content, out var botId))
|
||||
if (sender is not Panel panel
|
||||
|| panel.Children[0] is not Border border
|
||||
|| border.Child is not SKImageView botAvatar
|
||||
|| panel.Children[1] is not Button button
|
||||
|| button.Content is not Guid botId)
|
||||
throw new InvalidOperationException("Visual tree has an unexpected structure.");
|
||||
|
||||
// Set the avatar
|
||||
|
@ -132,7 +133,7 @@ public partial class LateralBarView : ReactiveUserControl<LateralBarViewModel>
|
|||
/// <exception cref="InvalidOperationException">Occurs when <paramref name="sender"/> is not a <see cref="Button"/>.</exception>
|
||||
private void DownsizeBotAvatar(object? sender, PointerPressedEventArgs eventArgs)
|
||||
{
|
||||
if (!Utilities.TryCastTo<Button>(sender, out var button))
|
||||
if (sender is not Button button)
|
||||
throw new InvalidOperationException($"Sender is not a {nameof(Button)}.");
|
||||
|
||||
var botAvatar = FindAvatarComponent(button);
|
||||
|
@ -149,7 +150,7 @@ public partial class LateralBarView : ReactiveUserControl<LateralBarViewModel>
|
|||
/// <exception cref="InvalidOperationException">Occurs when <paramref name="sender"/> is not a <see cref="Button"/>.</exception>
|
||||
private void UpsizeBotAvatar(object? sender, PointerReleasedEventArgs eventArgs)
|
||||
{
|
||||
if (!Utilities.TryCastTo<Button>(sender, out var button))
|
||||
if (sender is not Button button)
|
||||
throw new InvalidOperationException($"Sender is not a {nameof(Button)}.");
|
||||
|
||||
var botAvatar = FindAvatarComponent(button);
|
||||
|
@ -167,7 +168,7 @@ public partial class LateralBarView : ReactiveUserControl<LateralBarViewModel>
|
|||
/// <exception cref="InvalidOperationException">Occurs when the component's content is not a Guid.</exception>
|
||||
private SKImageView FindAvatarComponent<T>(T component) where T : ContentControl
|
||||
{
|
||||
return (!Utilities.TryCastTo<Guid>(component.Content, out var botId))
|
||||
return (component.Content is not Guid botId)
|
||||
? throw new InvalidOperationException($"{nameof(T)} does not contain a bot Id.")
|
||||
: FindAvatarComponent(botId);
|
||||
}
|
||||
|
|
|
@ -293,7 +293,7 @@ public partial class AppView : ReactiveWindow<AppViewModel>
|
|||
private static BotConfigViewModel GetBotConfigViewModel(Button button, IServiceScopeFactory scopeFactory)
|
||||
{
|
||||
using var scope = scopeFactory.CreateScope();
|
||||
var botId = (Guid)(button.Content ?? throw new InvalidOperationException("Bot button has no valid Id."));
|
||||
var botId = (button.Content ?? throw new InvalidOperationException("Bot button has no valid Id."));
|
||||
var botResolver = scope.ServiceProvider.GetParameterizedService<EllieResolver>(botId);
|
||||
|
||||
return scope.ServiceProvider.GetParameterizedService<BotConfigViewModel>(botResolver);
|
||||
|
|
|
@ -115,33 +115,9 @@ public sealed partial class EllieResolver : IBotResolver
|
|||
return null;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrWhiteSpace(botEntry.Version))
|
||||
return botEntry.Version;
|
||||
|
||||
// Ellie is published as a single-file binary, so we have to extract
|
||||
// its contents first in order to read the assembly for its version.
|
||||
using var executableReader = new ExecutableReader(executableUri);
|
||||
var extractDirectoryUri = Path.Combine(_tempDirectory, "EllieBotExtract");
|
||||
var extractAssemblyUri = Path.Combine(extractDirectoryUri, "EllieBot.dll");
|
||||
|
||||
try
|
||||
{
|
||||
await executableReader.ExtractToDirectoryAsync(extractDirectoryUri, cToken);
|
||||
|
||||
var nadekoAssembly = Assembly.LoadFile(extractAssemblyUri);
|
||||
var version = nadekoAssembly.GetName().Version
|
||||
?? throw new InvalidOperationException($"Could not find version of the assembly at {extractAssemblyUri}.");
|
||||
|
||||
var currentVersion = $"{version.Major}.{version.Minor}.{version.Build}";
|
||||
|
||||
await _appConfigManager.UpdateBotEntryAsync(Id, x => x with { Version = currentVersion }, cToken);
|
||||
|
||||
return currentVersion;
|
||||
}
|
||||
finally
|
||||
{
|
||||
Utilities.TryDeleteDirectory(extractDirectoryUri);
|
||||
}
|
||||
return (string.IsNullOrWhiteSpace(botEntry.Version))
|
||||
? await GetBotVersionFromAssemblyAsync(executableUri, cToken)
|
||||
: botEntry.Version;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -397,6 +373,51 @@ public sealed partial class EllieResolver : IBotResolver
|
|||
return response;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the bot version from the bot's assembly.
|
||||
/// </summary>
|
||||
/// <param name="executableUri">The path to the bot's executable file.</param>
|
||||
/// <param name="cToken">The cancellation token.</param>
|
||||
/// <returns>The version of the bot or <see langword="null"/> if the executable file is not found.</returns>
|
||||
/// <exception cref="InvalidOperationException">Occurs when the assembly file is not found.</exception>
|
||||
private async ValueTask<string?> GetBotVersionFromAssemblyAsync(string executableUri, CancellationToken cToken)
|
||||
{
|
||||
if (!File.Exists(executableUri))
|
||||
return null;
|
||||
|
||||
var directoryUri = Directory.GetParent(executableUri)?.FullName ?? Path.GetPathRoot(executableUri)!;
|
||||
var assemblyUri = Path.Join(directoryUri, "EllieBot.dll");
|
||||
var isSingleFile = !File.Exists(assemblyUri);
|
||||
|
||||
// If Ellie is published as a single-file binary, we have to extract
|
||||
// its contents first in order to read the assembly for its version.
|
||||
if (isSingleFile)
|
||||
{
|
||||
directoryUri = Path.Join(_tempDirectory, "EllieBotExtract_" + DateTimeOffset.Now.Ticks);
|
||||
assemblyUri = Path.Join(directoryUri, "EllieBot.dll");
|
||||
using var executableReader = new ExecutableReader(executableUri);
|
||||
await executableReader.ExtractToDirectoryAsync(directoryUri, cToken);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var ellieAssembly = Assembly.LoadFile(assemblyUri);
|
||||
var version = ellieAssembly.GetName().Version
|
||||
?? throw new InvalidOperationException($"Could not find version for the assembly at {assemblyUri}.");
|
||||
|
||||
var currentVersion = $"{version.Major}.{version.Minor}.{version.Build}";
|
||||
|
||||
await _appConfigManager.UpdateBotEntryAsync(Id, x => x with { Version = currentVersion }, cToken);
|
||||
|
||||
return currentVersion;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (isSingleFile)
|
||||
Utilities.TryDeleteDirectory(directoryUri);
|
||||
}
|
||||
}
|
||||
|
||||
[GeneratedRegex(@"^(?:\S+\-)(\S+\-\S+)\-", RegexOptions.Compiled)]
|
||||
private static partial Regex GenerateUnzipedDirRegex();
|
||||
}
|
|
@ -26,7 +26,7 @@ public partial class BotConfigView : ReactiveUserControl<BotConfigViewModel>
|
|||
/// <param name="eventArgs">The event arguments.</param>
|
||||
private void AvatarButtonHover(object? sender, PointerEventArgs eventArgs)
|
||||
{
|
||||
if (!Utilities.TryCastTo<Button>(sender, out var button))
|
||||
if (sender is not Button button)
|
||||
return;
|
||||
|
||||
button.Opacity = 3.0;
|
||||
|
@ -40,7 +40,7 @@ public partial class BotConfigView : ReactiveUserControl<BotConfigViewModel>
|
|||
/// <param name="eventArgs">The event arguments.</param>
|
||||
private void AvatarButtonUnhover(object? sender, PointerEventArgs eventArgs)
|
||||
{
|
||||
if (!Utilities.TryCastTo<Button>(sender, out var button))
|
||||
if (sender is not Button button)
|
||||
return;
|
||||
|
||||
button.Opacity = 0.0;
|
||||
|
|
|
@ -142,7 +142,7 @@ public sealed class AppResolver : IAppResolver
|
|||
|
||||
// Rename the original file from "file" to "file_old".
|
||||
if (File.Exists(destinationUri))
|
||||
File.Move(destinationUri, destinationUri + OldFileSuffix);
|
||||
File.Move(destinationUri, destinationUri + OldFileSuffix, true);
|
||||
|
||||
// Move the new file to the application's directory.
|
||||
if (Environment.OSVersion.Platform is not PlatformID.Unix)
|
||||
|
|
Loading…
Reference in a new issue