Skip to content

Commit

Permalink
Added simple Client for Microsoft Store
Browse files Browse the repository at this point in the history
No clue at all if it works, more doing this so I can plan out what I'm doing for clients

* Revert some BSDiff changes which caused it to break
* ICollection -> IReadOnlyCollection in IUpdatePackage
  • Loading branch information
Azyyyyyy committed Jan 14, 2024
1 parent 9a9b7d2 commit 86a2a29
Show file tree
Hide file tree
Showing 28 changed files with 265 additions and 112 deletions.
7 changes: 7 additions & 0 deletions TinyUpdate.sln
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TinyUpdate.Packages.Tests",
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TinyUpdate.Core.Tests", "tests\TinyUpdate.Core.Tests\TinyUpdate.Core.Tests.csproj", "{81B0A72E-04FA-4A4F-856F-68C22FF2D945}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TinyUpdate.MicrosoftStore", "src\Clients\TinyUpdate.MicrosoftStore\TinyUpdate.MicrosoftStore.csproj", "{F364F894-0AF5-4A42-A6D3-9B6A8C10E45B}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -72,6 +74,10 @@ Global
{81B0A72E-04FA-4A4F-856F-68C22FF2D945}.Debug|Any CPU.Build.0 = Debug|Any CPU
{81B0A72E-04FA-4A4F-856F-68C22FF2D945}.Release|Any CPU.ActiveCfg = Release|Any CPU
{81B0A72E-04FA-4A4F-856F-68C22FF2D945}.Release|Any CPU.Build.0 = Release|Any CPU
{F364F894-0AF5-4A42-A6D3-9B6A8C10E45B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F364F894-0AF5-4A42-A6D3-9B6A8C10E45B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F364F894-0AF5-4A42-A6D3-9B6A8C10E45B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F364F894-0AF5-4A42-A6D3-9B6A8C10E45B}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4B3D4412-9AF3-4D5A-B013-3462B46E815F} = {63F2556D-A89A-4552-84C7-D2BE30718485}
Expand All @@ -87,5 +93,6 @@ Global
{59769ABE-E512-43D0-B85B-37EF133DA27D} = {FFCB9AB6-92FE-48B0-9B93-A5BBF0DB153B}
{B5BC1A21-5A4C-403E-918B-CE48675E6F89} = {0BD356C4-B4F2-45D6-A94F-77ED1ECEEE11}
{81B0A72E-04FA-4A4F-856F-68C22FF2D945} = {0BD356C4-B4F2-45D6-A94F-77ED1ECEEE11}
{F364F894-0AF5-4A42-A6D3-9B6A8C10E45B} = {EE289D98-EE1C-4D17-9BB0-B4981E26A49D}
EndGlobalSection
EndGlobal
66 changes: 66 additions & 0 deletions src/Clients/TinyUpdate.MicrosoftStore/MicrosoftStoreClient.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
using Windows.Services.Store;
using Microsoft.Extensions.Logging;
using TinyUpdate.Core.Abstract;

namespace TinyUpdate.MicrosoftStore;

public class MicrosoftStoreClient(StoreContext storeContext, ILogger logger) : IPackageClient
{
public async Task<IEnumerable<ReleaseEntry>> GetUpdates()
{
var storePackageUpdates = await storeContext.GetAppAndOptionalStorePackageUpdatesAsync();
return [new MicrosoftStoreReleaseEntry(storePackageUpdates)];
}

public async Task<bool> DownloadUpdate(ReleaseEntry releaseEntry, IProgress<double>? progress)
{
if (releaseEntry is not MicrosoftStoreReleaseEntry microsoftStoreReleaseEntry)
{
logger.LogError("Wasn't given a microsoft store update entry");
return false;
}

var downloadOperation = storeContext.RequestDownloadStorePackageUpdatesAsync(microsoftStoreReleaseEntry
.StorePackageUpdates);

downloadOperation.Progress = (_, progressStatus) => progress?.Report(progressStatus.PackageDownloadProgress);

var downloadResult = await downloadOperation.AsTask();
return downloadResult.OverallState == StorePackageUpdateState.Completed;
}

public async Task<bool> ApplyUpdate(ReleaseEntry releaseEntry, IProgress<double>? progress)
{
//No need to actually do an update, report as successful
if (!releaseEntry.HasUpdate)
{
progress?.Report(1);
return true;
}

if (releaseEntry is not MicrosoftStoreReleaseEntry microsoftStoreReleaseEntry)
{
logger.LogError("Wasn't given a microsoft store update entry");
return false;
}

//TODO: Find out if the 0.8 - 1 applies here?
var installOperation = storeContext.RequestDownloadAndInstallStorePackageUpdatesAsync(microsoftStoreReleaseEntry
.StorePackageUpdates);

installOperation.Progress = (_, progressStatus) => progress?.Report(progressStatus.TotalDownloadProgress);
var installResult = await installOperation.AsTask();
return installResult.OverallState == StorePackageUpdateState.Completed;
}
}

public class MicrosoftStoreReleaseEntry : ReleaseEntry
{
public MicrosoftStoreReleaseEntry(IReadOnlyList<StorePackageUpdate>? storePackageUpdates)
{
StorePackageUpdates = storePackageUpdates ?? ArraySegment<StorePackageUpdate>.Empty;
}

public IReadOnlyList<StorePackageUpdate> StorePackageUpdates { get; }
public override bool HasUpdate => StorePackageUpdates.Count > 0;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>net8.0-windows10.0.17763.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\TinyUpdate.Core\TinyUpdate.Core.csproj" />
</ItemGroup>

</Project>
42 changes: 31 additions & 11 deletions src/Deltas/TinyUpdate.Delta.BSDiff/BSDiffDelta.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
using System.Buffers.Binary;
using Microsoft.Extensions.Logging;
using SharpCompress.Compressors;
using SharpCompress.Compressors.BZip2;
using TinyUpdate.Core.Abstract;
using TinyUpdate.Core.Abstract.Delta;

//TODO: Bring in changes from bsdiff.net into here
// Squirrel.Bsdiff: Adapted from https://github.com/LogosBible/bsdiff.net/blob/master/src/bsdiff/BinaryPatchUtility.cs
Expand Down Expand Up @@ -94,7 +93,8 @@ public async Task<bool> ApplyDeltaFile(Stream sourceStream, Stream deltaStream,
return false;
}

var patchMemoryStream = new MemoryStream();
//TODO: Check stream type passed
await using var patchMemoryStream = new MemoryStream();
await deltaStream.CopyToAsync(patchMemoryStream);

/*
Expand All @@ -115,7 +115,8 @@ with control block a set of triples (x,y,z) meaning "add x bytes
long controlLength, diffLength, newSize;
await using (var patchStream = CreatePatchStream())
{
var header = patchStream.ReadExactly(CHeaderSize);
var header = new byte[CHeaderSize];
patchStream.ReadExactly(header);

// check for appropriate magic
var signature = ReadInt64(header, 0);
Expand Down Expand Up @@ -450,7 +451,8 @@ private static bool SupportedStream(Stream deltaStream, out long newSize)
return false;
}

var header = deltaStream.ReadExactly(CHeaderSize);
var header = new byte[CHeaderSize];
deltaStream.ReadExactly(header);

// check for appropriate magic
var signature = ReadInt64(header, 0);
Expand Down Expand Up @@ -675,14 +677,32 @@ private static int[] SuffixSort(byte[] oldData)

private static long ReadInt64(byte[] buf, int offset)
{
var value = BinaryPrimitives.ReadInt64LittleEndian(buf);
var mask = value >> 63;
return (~mask & value) | (((value & unchecked((long) 0x8000_0000_0000_0000)) - value) & mask);
}
long value = buf[offset + 7] & 0x7F;

for (var index = 6; index >= 0; index--)
{
value *= 256;
value += buf[offset + index];
}

if ((buf[offset + 7] & 0x80) != 0)
value = -value;

return value;
}

private static void WriteInt64(long value, byte[] buf, int offset)
{
var mask = value >> 63;
BinaryPrimitives.WriteInt64LittleEndian(buf, ((value + mask) ^ mask) | (value & unchecked((long) 0x8000_0000_0000_0000)));
var valueToWrite = value < 0 ? -value : value;

for (var byteIndex = 0; byteIndex < 8; byteIndex++)
{
buf[offset + byteIndex] = (byte)(valueToWrite % 256);
valueToWrite -= buf[offset + byteIndex];
valueToWrite /= 256;
}

if (value < 0)
buf[offset + 7] |= 0x80;
}
}
22 changes: 0 additions & 22 deletions src/Deltas/TinyUpdate.Delta.BSDiff/StreamUtility.cs

This file was deleted.

3 changes: 1 addition & 2 deletions src/Deltas/TinyUpdate.Delta.MSDelta/MSDelta.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
using System.Runtime.InteropServices;
using System.Text;
using TinyUpdate.Core.Abstract;
using TinyUpdate.Core.Abstract.Delta;
using TinyUpdate.Delta.MSDelta.Enum;
using TinyUpdate.Delta.MSDelta.Struct;

Expand Down
1 change: 0 additions & 1 deletion src/Packages/TinyUpdate.TUUP/FileEntryExt.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
using TinyUpdate.Core;
using TinyUpdate.Core.Model;

namespace TinyUpdate.TUUP;
Expand Down
30 changes: 19 additions & 11 deletions src/Packages/TinyUpdate.TUUP/TuupUpdatePackage.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.IO.Compression;
using TinyUpdate.Core;
using TinyUpdate.Core.Abstract;
using TinyUpdate.Core.Abstract.Delta;
using TinyUpdate.Core.Model;

namespace TinyUpdate.TUUP;
Expand All @@ -18,10 +18,10 @@ public class TuupUpdatePackage(IDeltaManager deltaManager, IHasher hasher) : IUp
private ZipArchive? _zipArchive;

public string Extension => Consts.TuupExtension;
public ICollection<FileEntry> DeltaFiles { get; } = new List<FileEntry>();
public ICollection<FileEntry> UnchangedFiles { get; } = new List<FileEntry>();
public ICollection<FileEntry> NewFiles { get; } = new List<FileEntry>();
public ICollection<FileEntry> MovedFiles { get; } = new List<FileEntry>();
public IReadOnlyCollection<FileEntry> DeltaFiles { get; private set; } = ArraySegment<FileEntry>.Empty;
public IReadOnlyCollection<FileEntry> UnchangedFiles { get; private set; } = ArraySegment<FileEntry>.Empty;
public IReadOnlyCollection<FileEntry> NewFiles { get; private set; } = ArraySegment<FileEntry>.Empty;
public IReadOnlyCollection<FileEntry> MovedFiles { get; private set; } = ArraySegment<FileEntry>.Empty;

public async Task Load(Stream updatePackageStream)
{
Expand All @@ -33,31 +33,39 @@ public async Task Load(Stream updatePackageStream)
{
throw new InvalidDataException("TuupUpdatePackage expects a zip formatted package", e);
}


var deltaFiles = new List<FileEntry>();
var unchangedFiles = new List<FileEntry>();
var newFiles = new List<FileEntry>();
var movedFiles = new List<FileEntry>();
await foreach (var fileEntry in GetFilesFromPackage(_zipArchive))
{
//Add to the correct collection
if (fileEntry.IsDeltaFile())
{
DeltaFiles.Add(fileEntry);
deltaFiles.Add(fileEntry);
continue;
}

if (fileEntry.IsNewFile())
{
NewFiles.Add(fileEntry);
newFiles.Add(fileEntry);
continue;
}

if (fileEntry.HasFileMoved())
{
MovedFiles.Add(fileEntry);
movedFiles.Add(fileEntry);
continue;
}

UnchangedFiles.Add(fileEntry);
unchangedFiles.Add(fileEntry);
}

DeltaFiles = deltaFiles;
UnchangedFiles = unchangedFiles;
NewFiles = newFiles;
MovedFiles = movedFiles;
_loaded = true;
}

Expand All @@ -67,7 +75,7 @@ public async Task Load(Stream updatePackageStream)
/// <param name="zip"><see cref="ZipArchive" /> that contains all the files</param>
private async IAsyncEnumerable<FileEntry> GetFilesFromPackage(ZipArchive zip)
{
var fileEntriesData = new Dictionary<string, Dictionary<string, object?>>(zip.Entries.Count);
var fileEntriesData = new Dictionary<string, Dictionary<string, object?>>(zip.Entries.Count / 2);
foreach (var zipEntry in zip.Entries)
{
//Check if the name contains a extension
Expand Down
13 changes: 7 additions & 6 deletions src/Packages/TinyUpdate.TUUP/TuupUpdatePackageCreator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
using NeoSmart.AsyncLock;
using SemVersion;
using TinyUpdate.Core.Abstract;
using TinyUpdate.Core.Abstract.Delta;

namespace TinyUpdate.TUUP;

/// <summary>
/// Update package creator for <see cref="TuupUpdatePackage"/>
/// </summary>
public class TuupUpdatePackageCreator : IUpdatePackageCreator
public class TuupUpdatePackageCreator : IDeltaUpdatePackageCreator, IUpdatePackageCreator
{
private readonly AsyncLock _zipLock;
private readonly IHasher _hasher;
Expand Down Expand Up @@ -151,17 +152,17 @@ async Task AddMovedPathFile(string newFilePath, string previousFileLocation)
async Task GetHashes(IDictionary<string, List<string>> hashes, IEnumerable<string> files)
{
//We want to get a hash of all the old files, this allows us to detect files which have moved
foreach (var oldFile in files)
foreach (var fileLocation in files)
{
await using var previousFileContentStream = File.OpenRead(oldFile);
var hash = _hasher.HashData(previousFileContentStream);
await using var fileContentStream = File.OpenRead(fileLocation);
var hash = _hasher.HashData(fileContentStream);
if (!hashes.TryGetValue(hash, out var filesList))
{
filesList = new List<string>();
hashes.Add(hash, filesList);
}

filesList.Add(oldFile);
filesList.Add(fileLocation);
}
}

Expand Down Expand Up @@ -202,7 +203,7 @@ private async Task<bool> AddFile(ZipArchive zipArchive, Stream fileContentStream
return true;
}

private void CheckFilePath(ref string filepath)
private static void CheckFilePath(ref string filepath)
{
if (Path.DirectorySeparatorChar != '\\')
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace TinyUpdate.Core.Abstract;
namespace TinyUpdate.Core.Abstract.Delta;

/// <summary>
/// Provides base functionality for applying delta updates
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace TinyUpdate.Core.Abstract;
namespace TinyUpdate.Core.Abstract.Delta;

/// <summary>
/// Provides base functionality for creating delta updates
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using TinyUpdate.Core.Model;

namespace TinyUpdate.Core.Abstract;
namespace TinyUpdate.Core.Abstract.Delta;

/// <summary>
/// Manages delta processing for external packages
Expand Down
27 changes: 27 additions & 0 deletions src/TinyUpdate.Core/Abstract/Delta/IDeltaUpdatePackageCreator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
using SemVersion;

namespace TinyUpdate.Core.Abstract.Delta;

/// <summary>
/// Provides base functionality for creating delta update packages
/// </summary>
public interface IDeltaUpdatePackageCreator : IExtension
{
/// <summary>
/// Template for a delta package filename (Null if not supported)
/// </summary>
string DeltaPackageFilenameTemplate { get; }

/// <summary>
/// Creates a delta update package
/// </summary>
/// <param name="previousApplicationLocation">Where the previous version of the application is located</param>
/// <param name="previousApplicationVersion">What the previous version of the application is</param>
/// <param name="newApplicationLocation">Where the new version of the application is located</param>
/// <param name="newApplicationVersion">What the new version of the application is</param>
/// <param name="updatePackageLocation">Where we should store the created update package</param>
/// <param name="applicationName">The applications name</param>
/// <param name="progress">Process about creating the update package</param>
/// <returns>If we successfully created the update package</returns>
Task<bool> CreateDeltaPackage(string previousApplicationLocation, SemanticVersion previousApplicationVersion, string newApplicationLocation, SemanticVersion newApplicationVersion, string updatePackageLocation, string applicationName, IProgress<double>? progress = null);
}
Loading

0 comments on commit 86a2a29

Please sign in to comment.