beginnings of v4.8.0.0
- Minor refactoring - Added an HTTP content cache - Replaced Onova with custom update functionality (work in progress)
This commit is contained in:
parent
52e82e2397
commit
74c5588d64
9 changed files with 219 additions and 249 deletions
|
@ -4,7 +4,7 @@
|
||||||
<TargetFramework>net7.0-windows</TargetFramework>
|
<TargetFramework>net7.0-windows</TargetFramework>
|
||||||
<UseWindowsForms>True</UseWindowsForms>
|
<UseWindowsForms>True</UseWindowsForms>
|
||||||
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
<ApplicationIcon>Resources\ini.ico</ApplicationIcon>
|
||||||
<Version>4.7.1.3</Version>
|
<Version>4.8.0.0</Version>
|
||||||
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
<Copyright>2021, pointfeev (https://github.com/pointfeev)</Copyright>
|
||||||
<Company>CreamInstaller</Company>
|
<Company>CreamInstaller</Company>
|
||||||
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
<Product>Automatic DLC Unlocker Installer & Configuration Generator</Product>
|
||||||
|
@ -147,7 +147,6 @@
|
||||||
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" />
|
<PackageReference Include="Gameloop.Vdf" Version="0.6.2" />
|
||||||
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
|
<PackageReference Include="HtmlAgilityPack" Version="1.11.46" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.2" />
|
||||||
<PackageReference Include="Onova" Version="2.6.6" />
|
|
||||||
<PackageReference Include="System.ServiceModel.Primitives" Version="4.10.0" />
|
<PackageReference Include="System.ServiceModel.Primitives" Version="4.10.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -1,240 +0,0 @@
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Web;
|
|
||||||
using System.Windows.Forms;
|
|
||||||
using CreamInstaller.Components;
|
|
||||||
using CreamInstaller.Utility;
|
|
||||||
using HtmlAgilityPack;
|
|
||||||
using Onova;
|
|
||||||
using Onova.Models;
|
|
||||||
using Onova.Services;
|
|
||||||
|
|
||||||
namespace CreamInstaller.Forms;
|
|
||||||
|
|
||||||
internal sealed partial class MainForm : CustomForm
|
|
||||||
{
|
|
||||||
private CancellationTokenSource cancellationTokenSource;
|
|
||||||
private Version latestVersion;
|
|
||||||
|
|
||||||
private UpdateManager updateManager;
|
|
||||||
private IReadOnlyList<Version> versions;
|
|
||||||
|
|
||||||
internal MainForm()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
Text = Program.ApplicationNameShort;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void StartProgram()
|
|
||||||
{
|
|
||||||
if (cancellationTokenSource is not null)
|
|
||||||
{
|
|
||||||
cancellationTokenSource.Cancel();
|
|
||||||
cancellationTokenSource.Dispose();
|
|
||||||
cancellationTokenSource = null;
|
|
||||||
}
|
|
||||||
#pragma warning disable CA2000 // Dispose objects before losing scope
|
|
||||||
SelectForm form = new();
|
|
||||||
#pragma warning restore CA2000 // Dispose objects before losing scope
|
|
||||||
form.InheritLocation(this);
|
|
||||||
form.FormClosing += (_, _) => Close();
|
|
||||||
form.Show();
|
|
||||||
Hide();
|
|
||||||
#if DEBUG
|
|
||||||
DebugForm.Current.Attach(form);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void OnLoad()
|
|
||||||
{
|
|
||||||
progressBar.Visible = false;
|
|
||||||
ignoreButton.Visible = true;
|
|
||||||
updateButton.Text = "Update";
|
|
||||||
updateButton.Click -= OnUpdateCancel;
|
|
||||||
progressLabel.Text = "Checking for updates . . .";
|
|
||||||
changelogTreeView.Visible = false;
|
|
||||||
changelogTreeView.Location = progressLabel.Location with { Y = progressLabel.Location.Y + progressLabel.Size.Height + 13 };
|
|
||||||
Refresh();
|
|
||||||
#if DEBUG
|
|
||||||
DebugForm.Current.Attach(this);
|
|
||||||
#endif
|
|
||||||
GithubPackageResolver resolver = new(Program.RepositoryOwner, Program.RepositoryName, Program.RepositoryPackage);
|
|
||||||
ZipPackageExtractor extractor = new();
|
|
||||||
updateManager = new(AssemblyMetadata.FromAssembly(Program.EntryAssembly, Program.CurrentProcessFilePath), resolver, extractor);
|
|
||||||
if (latestVersion is null)
|
|
||||||
{
|
|
||||||
cancellationTokenSource = new();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
CheckForUpdatesResult checkForUpdatesResult = await updateManager.CheckForUpdatesAsync(cancellationTokenSource.Token);
|
|
||||||
#if !DEBUG
|
|
||||||
if (checkForUpdatesResult.CanUpdate)
|
|
||||||
{
|
|
||||||
#endif
|
|
||||||
latestVersion = checkForUpdatesResult.LastVersion;
|
|
||||||
versions = checkForUpdatesResult.Versions;
|
|
||||||
#if !DEBUG
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
#if DEBUG
|
|
||||||
catch (TaskCanceledException) { }
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
DebugForm.Current.Log($"Exception while checking for updates: {e.GetType()} ({e.Message})", LogTextBox.Warning);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
cancellationTokenSource.Dispose();
|
|
||||||
cancellationTokenSource = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (latestVersion is null)
|
|
||||||
{
|
|
||||||
updateManager.Dispose();
|
|
||||||
updateManager = null;
|
|
||||||
StartProgram();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
progressLabel.Text = $"An update is available: v{latestVersion}";
|
|
||||||
ignoreButton.Enabled = true;
|
|
||||||
updateButton.Enabled = true;
|
|
||||||
updateButton.Click += OnUpdate;
|
|
||||||
changelogTreeView.Visible = true;
|
|
||||||
Version currentVersion = new(Program.Version);
|
|
||||||
#if DEBUG
|
|
||||||
foreach (Version version in versions.Where(v => (v > currentVersion || v == latestVersion) && !changelogTreeView.Nodes.ContainsKey(v.ToString())))
|
|
||||||
#else
|
|
||||||
foreach (Version version in versions.Where(v => v > currentVersion && !changelogTreeView.Nodes.ContainsKey(v.ToString())))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
TreeNode root = new($"v{version}") { Name = version.ToString() };
|
|
||||||
changelogTreeView.Nodes.Add(root);
|
|
||||||
if (changelogTreeView.Nodes.Count > 0)
|
|
||||||
changelogTreeView.Nodes[0].EnsureVisible();
|
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
HtmlNodeCollection nodes = await HttpClientManager.GetDocumentNodes(
|
|
||||||
$"https://github.com/{Program.RepositoryOwner}/{Program.RepositoryName}/releases/tag/v{version}",
|
|
||||||
"//div[@data-test-selector='body-content']/ul/li");
|
|
||||||
if (nodes is null)
|
|
||||||
changelogTreeView.Nodes.Remove(root);
|
|
||||||
else
|
|
||||||
foreach (HtmlNode node in nodes)
|
|
||||||
changelogTreeView.Invoke(delegate
|
|
||||||
{
|
|
||||||
TreeNode change = new() { Text = HttpUtility.HtmlDecode(node.InnerText) ?? string.Empty };
|
|
||||||
root.Nodes.Add(change);
|
|
||||||
root.Expand();
|
|
||||||
if (changelogTreeView.Nodes.Count > 0)
|
|
||||||
changelogTreeView.Nodes[0].EnsureVisible();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLoad(object sender, EventArgs _)
|
|
||||||
{
|
|
||||||
retry:
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string fileName = Path.GetFileName(Program.CurrentProcessFilePath);
|
|
||||||
if (fileName != Program.ApplicationExecutable)
|
|
||||||
{
|
|
||||||
using DialogForm form = new(this);
|
|
||||||
if (form.Show(SystemIcons.Warning,
|
|
||||||
"WARNING: " + Program.ApplicationExecutable + " was renamed!" + "\n\nThis will cause undesirable behavior when updating the program!",
|
|
||||||
"Ignore", "Abort") == DialogResult.Cancel)
|
|
||||||
{
|
|
||||||
Application.Exit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
OnLoad();
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
if (e.HandleException(this))
|
|
||||||
goto retry;
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnIgnore(object sender, EventArgs e) => StartProgram();
|
|
||||||
|
|
||||||
private async void OnUpdate(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
progressBar.Visible = true;
|
|
||||||
ignoreButton.Visible = false;
|
|
||||||
updateButton.Text = "Cancel";
|
|
||||||
updateButton.Click -= OnUpdate;
|
|
||||||
updateButton.Click += OnUpdateCancel;
|
|
||||||
changelogTreeView.Location = progressBar.Location with { Y = progressBar.Location.Y + progressBar.Size.Height + 6 };
|
|
||||||
Refresh();
|
|
||||||
Progress<double> progress = new();
|
|
||||||
progress.ProgressChanged += delegate(object _, double _progress)
|
|
||||||
{
|
|
||||||
progressLabel.Text = $"Updating . . . {(int)_progress}%";
|
|
||||||
progressBar.Value = (int)_progress;
|
|
||||||
};
|
|
||||||
progressLabel.Text = "Updating . . . ";
|
|
||||||
cancellationTokenSource = new();
|
|
||||||
try
|
|
||||||
{
|
|
||||||
await updateManager.PrepareUpdateAsync(latestVersion, progress, cancellationTokenSource.Token);
|
|
||||||
}
|
|
||||||
#if DEBUG
|
|
||||||
catch (TaskCanceledException) { }
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
DebugForm.Current.Log($"Exception while preparing update: {ex.GetType()} ({ex.Message})", LogTextBox.Warning);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
cancellationTokenSource.Dispose();
|
|
||||||
cancellationTokenSource = null;
|
|
||||||
}
|
|
||||||
if (updateManager is not null && updateManager.IsUpdatePrepared(latestVersion))
|
|
||||||
{
|
|
||||||
updateManager.LaunchUpdater(latestVersion);
|
|
||||||
Application.Exit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
OnLoad();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnUpdateCancel(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
cancellationTokenSource?.Cancel();
|
|
||||||
updateManager?.Dispose();
|
|
||||||
updateManager = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
components?.Dispose();
|
|
||||||
base.Dispose(disposing);
|
|
||||||
cancellationTokenSource?.Dispose();
|
|
||||||
updateManager?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ using CreamInstaller.Components;
|
||||||
|
|
||||||
namespace CreamInstaller.Forms
|
namespace CreamInstaller.Forms
|
||||||
{
|
{
|
||||||
partial class MainForm
|
partial class UpdateForm
|
||||||
{
|
{
|
||||||
private IContainer components = null;
|
private IContainer components = null;
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ namespace CreamInstaller.Forms
|
||||||
this.changelogTreeView.Sorted = true;
|
this.changelogTreeView.Sorted = true;
|
||||||
this.changelogTreeView.TabIndex = 5;
|
this.changelogTreeView.TabIndex = 5;
|
||||||
//
|
//
|
||||||
// MainForm
|
// UpdateForm
|
||||||
//
|
//
|
||||||
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F);
|
||||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||||
|
@ -94,9 +94,9 @@ namespace CreamInstaller.Forms
|
||||||
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||||
this.MaximizeBox = false;
|
this.MaximizeBox = false;
|
||||||
this.MinimizeBox = false;
|
this.MinimizeBox = false;
|
||||||
this.Name = "MainForm";
|
this.Name = "UpdateForm";
|
||||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||||
this.Text = "MainForm";
|
this.Text = "UpdateForm";
|
||||||
this.Load += new System.EventHandler(this.OnLoad);
|
this.Load += new System.EventHandler(this.OnLoad);
|
||||||
this.ResumeLayout(false);
|
this.ResumeLayout(false);
|
||||||
|
|
152
CreamInstaller/Forms/UpdateForm.cs
Normal file
152
CreamInstaller/Forms/UpdateForm.cs
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
using CreamInstaller.Components;
|
||||||
|
using CreamInstaller.Utility;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace CreamInstaller.Forms;
|
||||||
|
|
||||||
|
internal sealed partial class UpdateForm : CustomForm
|
||||||
|
{
|
||||||
|
private Release latestRelease;
|
||||||
|
|
||||||
|
internal UpdateForm()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
Text = Program.ApplicationNameShort;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StartProgram()
|
||||||
|
{
|
||||||
|
SelectForm form = new();
|
||||||
|
form.InheritLocation(this);
|
||||||
|
form.FormClosing += (_, _) => Close();
|
||||||
|
form.Show();
|
||||||
|
Hide();
|
||||||
|
#if DEBUG
|
||||||
|
DebugForm.Current.Attach(form);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnLoad()
|
||||||
|
{
|
||||||
|
progressBar.Visible = false;
|
||||||
|
ignoreButton.Visible = true;
|
||||||
|
updateButton.Text = "Update";
|
||||||
|
updateButton.Click -= OnUpdateCancel;
|
||||||
|
progressLabel.Text = "Checking for updates . . .";
|
||||||
|
changelogTreeView.Visible = false;
|
||||||
|
changelogTreeView.Location = progressLabel.Location with { Y = progressLabel.Location.Y + progressLabel.Size.Height + 13 };
|
||||||
|
Refresh();
|
||||||
|
#if !DEBUG
|
||||||
|
Version currentVersion = new(Program.Version);
|
||||||
|
#endif
|
||||||
|
List<Release> releases = null;
|
||||||
|
string response = await HttpClientManager.EnsureGet($"https://api.github.com/repos/{Program.RepositoryOwner}/{Program.RepositoryName}/releases");
|
||||||
|
if (response is not null)
|
||||||
|
releases = JsonConvert.DeserializeObject<List<Release>>(response)
|
||||||
|
?.Where(release => !release.Draft && !release.Prerelease && release.Assets.Count > 0).ToList();
|
||||||
|
latestRelease = releases?.FirstOrDefault();
|
||||||
|
#if DEBUG
|
||||||
|
if (latestRelease?.Version is not { } latestVersion)
|
||||||
|
#else
|
||||||
|
if (latestRelease?.Version is not { } latestVersion || latestVersion <= currentVersion)
|
||||||
|
#endif
|
||||||
|
StartProgram();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
progressLabel.Text = $"An update is available: v{latestVersion}";
|
||||||
|
ignoreButton.Enabled = true;
|
||||||
|
updateButton.Enabled = true;
|
||||||
|
updateButton.Click += OnUpdate;
|
||||||
|
changelogTreeView.Visible = true;
|
||||||
|
for (int r = releases!.Count - 1; r >= 0; r--)
|
||||||
|
{
|
||||||
|
Release release = releases[r];
|
||||||
|
#if !DEBUG
|
||||||
|
if (release.Version <= currentVersion)
|
||||||
|
continue;
|
||||||
|
#endif
|
||||||
|
TreeNode root = new(release.Name) { Name = release.Name };
|
||||||
|
changelogTreeView.Nodes.Add(root);
|
||||||
|
if (changelogTreeView.Nodes.Count > 0)
|
||||||
|
changelogTreeView.Nodes[0].EnsureVisible();
|
||||||
|
for (int i = release.Changes.Length - 1; i >= 0; i--)
|
||||||
|
changelogTreeView.Invoke(delegate
|
||||||
|
{
|
||||||
|
string change = release.Changes[i];
|
||||||
|
TreeNode changeNode = new() { Text = change };
|
||||||
|
root.Nodes.Add(changeNode);
|
||||||
|
root.Expand();
|
||||||
|
if (changelogTreeView.Nodes.Count > 0)
|
||||||
|
changelogTreeView.Nodes[0].EnsureVisible();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnLoad(object sender, EventArgs _)
|
||||||
|
{
|
||||||
|
retry:
|
||||||
|
try
|
||||||
|
{
|
||||||
|
string fileName = Path.GetFileName(Program.CurrentProcessFilePath);
|
||||||
|
if (fileName != Program.ApplicationExecutable)
|
||||||
|
{
|
||||||
|
using DialogForm form = new(this);
|
||||||
|
if (form.Show(SystemIcons.Warning,
|
||||||
|
"WARNING: " + Program.ApplicationExecutable + " was renamed!" + "\n\nThis will cause undesirable behavior when updating the program!",
|
||||||
|
"Ignore", "Abort") == DialogResult.Cancel)
|
||||||
|
{
|
||||||
|
Application.Exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
OnLoad();
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
if (e.HandleException(this))
|
||||||
|
goto retry;
|
||||||
|
Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnIgnore(object sender, EventArgs e) => StartProgram();
|
||||||
|
|
||||||
|
private void OnUpdate(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
progressBar.Visible = true;
|
||||||
|
ignoreButton.Visible = false;
|
||||||
|
updateButton.Text = "Cancel";
|
||||||
|
updateButton.Click -= OnUpdate;
|
||||||
|
updateButton.Click += OnUpdateCancel;
|
||||||
|
changelogTreeView.Location = progressBar.Location with { Y = progressBar.Location.Y + progressBar.Size.Height + 6 };
|
||||||
|
Refresh();
|
||||||
|
Progress<double> progress = new();
|
||||||
|
progress.ProgressChanged += delegate(object _, double _progress)
|
||||||
|
{
|
||||||
|
progressLabel.Text = $"Updating . . . {(int)_progress}%";
|
||||||
|
progressBar.Value = (int)_progress;
|
||||||
|
};
|
||||||
|
progressLabel.Text = "Updating . . . ";
|
||||||
|
// do update
|
||||||
|
OnLoad();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnUpdateCancel(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
// cancel update
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
components?.Dispose();
|
||||||
|
base.Dispose(disposing);
|
||||||
|
}
|
||||||
|
}
|
|
@ -40,7 +40,7 @@ internal static class SteamStore
|
||||||
string response = await HttpClientManager.EnsureGet($"https://store.steampowered.com/api/appdetails?appids={appId}");
|
string response = await HttpClientManager.EnsureGet($"https://store.steampowered.com/api/appdetails?appids={appId}");
|
||||||
if (response is not null)
|
if (response is not null)
|
||||||
{
|
{
|
||||||
IDictionary<string, JToken> apps = (IDictionary<string, JToken>)JsonConvert.DeserializeObject(response);
|
Dictionary<string, JToken> apps = JsonConvert.DeserializeObject<Dictionary<string, JToken>>(response);
|
||||||
if (apps is not null)
|
if (apps is not null)
|
||||||
foreach (KeyValuePair<string, JToken> app in apps)
|
foreach (KeyValuePair<string, JToken> app in apps)
|
||||||
try
|
try
|
||||||
|
|
|
@ -86,7 +86,7 @@ internal static class Program
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
HttpClientManager.Setup();
|
HttpClientManager.Setup();
|
||||||
using MainForm form = new();
|
using UpdateForm form = new();
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
DebugForm.Current.Attach(form);
|
DebugForm.Current.Attach(form);
|
||||||
#endif
|
#endif
|
||||||
|
|
52
CreamInstaller/Release.cs
Normal file
52
CreamInstaller/Release.cs
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace CreamInstaller;
|
||||||
|
|
||||||
|
public class Release
|
||||||
|
{
|
||||||
|
private string[] changes;
|
||||||
|
|
||||||
|
private Version version;
|
||||||
|
|
||||||
|
[JsonProperty("tag_name", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public string TagName { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("draft", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public bool Draft { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("prerelease", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public bool Prerelease { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("assets", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public List<Asset> Assets { get; } = new();
|
||||||
|
|
||||||
|
[JsonProperty("body", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public string Body { get; set; }
|
||||||
|
|
||||||
|
public Version Version => version ??= new(TagName[1..]);
|
||||||
|
|
||||||
|
public string[] Changes => changes ??= Body.Replace("- ", "").Split("\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
public class Asset
|
||||||
|
{
|
||||||
|
[JsonProperty("name", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public string Name { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("content_type", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public string ContentType { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("state", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public string State { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("size", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public int Size { get; set; }
|
||||||
|
|
||||||
|
[JsonProperty("browser_download_url", NullValueHandling = NullValueHandling.Ignore)]
|
||||||
|
public string BrowserDownloadUrl { get; set; }
|
||||||
|
}
|
|
@ -1,4 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
|
@ -14,6 +15,8 @@ internal static class HttpClientManager
|
||||||
{
|
{
|
||||||
internal static HttpClient HttpClient;
|
internal static HttpClient HttpClient;
|
||||||
|
|
||||||
|
private static readonly Dictionary<string, string> HttpContentCache = new();
|
||||||
|
|
||||||
internal static void Setup()
|
internal static void Setup()
|
||||||
{
|
{
|
||||||
HttpClient = new();
|
HttpClient = new();
|
||||||
|
@ -26,8 +29,12 @@ internal static class HttpClientManager
|
||||||
{
|
{
|
||||||
using HttpRequestMessage request = new(HttpMethod.Get, url);
|
using HttpRequestMessage request = new(HttpMethod.Get, url);
|
||||||
using HttpResponseMessage response = await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
using HttpResponseMessage response = await HttpClient.SendAsync(request, HttpCompletionOption.ResponseHeadersRead);
|
||||||
|
if (response.StatusCode is HttpStatusCode.NotModified && HttpContentCache.TryGetValue(url, out string content))
|
||||||
|
return content;
|
||||||
_ = response.EnsureSuccessStatusCode();
|
_ = response.EnsureSuccessStatusCode();
|
||||||
return await response.Content.ReadAsStringAsync();
|
content = await response.Content.ReadAsStringAsync();
|
||||||
|
HttpContentCache[url] = content;
|
||||||
|
return content;
|
||||||
}
|
}
|
||||||
catch (HttpRequestException e)
|
catch (HttpRequestException e)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in a new issue