Added SelfUpdate
This commit is contained in:
@@ -21,6 +21,19 @@ public static class Entry
|
||||
|
||||
File.Delete("./Data/Resources/plugins.json");
|
||||
Directory.Delete("./Libraries/", true);
|
||||
}),
|
||||
|
||||
new StartupAction("--update-cleanup", () => {
|
||||
List<string> files = new List<string>();
|
||||
files.AddRange(Directory.GetFiles("./"));
|
||||
|
||||
foreach (var file in files)
|
||||
{
|
||||
if (file.EndsWith(".bak"))
|
||||
File.Delete(file);
|
||||
}
|
||||
|
||||
Directory.Delete("temp");
|
||||
})
|
||||
];
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DiscordBot.Bot.Actions.Extra;
|
||||
|
||||
using DiscordBot.Utilities;
|
||||
using DiscordBotCore;
|
||||
using DiscordBotCore.Bot;
|
||||
using DiscordBotCore.Others;
|
||||
@@ -83,19 +83,14 @@ public class Program
|
||||
{
|
||||
await Application.CreateApplication();
|
||||
|
||||
AppUpdater updater = new();
|
||||
var update = await updater.CheckForUpdates();
|
||||
|
||||
if (update != Update.None)
|
||||
AppUpdater updater = new AppUpdater();
|
||||
Update? update = await updater.PrepareUpdate();
|
||||
if(update is not null)
|
||||
{
|
||||
Console.WriteLine($"New update available: {update.UpdateVersion}");
|
||||
Console.WriteLine($"Download link: {update.UpdateUrl}");
|
||||
Console.WriteLine($"Update notes: {update.UpdateNotes}\n\n");
|
||||
|
||||
Console.WriteLine("Waiting 5 seconds ...");
|
||||
await Task.Delay(5000);
|
||||
await ConsoleUtilities.ExecuteTaskWithBuiltInProgress(updater.SelfUpdate, update, "Discord Bot Update");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
Application.CurrentApplication.Logger.OnFormattedLog += (sender, logMessage) =>
|
||||
{
|
||||
var messageColor = logMessage.Type switch
|
||||
|
||||
@@ -12,5 +12,11 @@ namespace DiscordBot
|
||||
this.Command = command;
|
||||
this.RunAction = runAction;
|
||||
}
|
||||
|
||||
public StartupAction(string command, Action runAction)
|
||||
{
|
||||
this.Command = command;
|
||||
this.RunAction = (args) => runAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using DiscordBotCore.Updater.Application;
|
||||
using Spectre.Console;
|
||||
|
||||
namespace DiscordBot.Utilities;
|
||||
@@ -27,4 +28,22 @@ internal static class ConsoleUtilities
|
||||
return result;
|
||||
}
|
||||
|
||||
public static async Task ExecuteTaskWithBuiltInProgress<T>(Func<T, IProgress<float>, Task> method, T parameter, string taskMessage)
|
||||
{
|
||||
await AnsiConsole.Progress()
|
||||
.AutoClear(false) // Do not remove the task list when done
|
||||
.HideCompleted(false) // Hide tasks as they are completed
|
||||
.Columns(new TaskDescriptionColumn(), new ProgressBarColumn(), new PercentageColumn())
|
||||
.StartAsync(
|
||||
async ctx =>
|
||||
{
|
||||
var task = ctx.AddTask(taskMessage);
|
||||
IProgress<float> progress = new Progress<float>(x => task.Value = x);
|
||||
await method(parameter, progress);
|
||||
task.Value = 100;
|
||||
}
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,15 +5,12 @@ namespace DiscordBotCore.Interfaces.Updater
|
||||
{
|
||||
public class AppVersion : IVersion
|
||||
{
|
||||
public int Major { get; set; }
|
||||
|
||||
public int Minor { get; set; }
|
||||
|
||||
public int Patch { get; set; }
|
||||
|
||||
public int PatchVersion { get; set; }
|
||||
|
||||
public static readonly AppVersion CurrentAppVersion = new AppVersion(Assembly.GetEntryAssembly().GetName().Version.ToString());
|
||||
|
||||
public int Major { get; set; }
|
||||
public int Minor { get; set; }
|
||||
public int Patch { get; set; }
|
||||
public int PatchVersion { get; set; }
|
||||
|
||||
private readonly char _Separator = '.';
|
||||
|
||||
|
||||
@@ -150,7 +150,10 @@ public static class ArchiveManager
|
||||
|
||||
try
|
||||
{
|
||||
entry.ExtractToFile(Path.Combine(folder, entry.FullName), true);
|
||||
string path = Path.Combine(folder, entry.FullName);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
|
||||
entry.ExtractToFile(path, true);
|
||||
currentSize += (ulong)entry.CompressedLength;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
@@ -1,93 +1,126 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using DiscordBotCore.Interfaces.Updater;
|
||||
using DiscordBotCore.Online;
|
||||
using DiscordBotCore.Others;
|
||||
|
||||
namespace DiscordBotCore.Updater.Application
|
||||
{
|
||||
public class AppUpdater
|
||||
{
|
||||
private static readonly string _DefaultUpdateUrl = "https://github.com/andreitdr/SethDiscordBot/releases/latest";
|
||||
|
||||
const string ProjectName = "SethDiscordBot";
|
||||
|
||||
private static readonly string _DefaultUpdateUrl = $"https://github.com/andreitdr/{ProjectName}/releases/latest";
|
||||
private static readonly string _DefaultUpdateDownloadUrl = $"https://github.com/andreitdr/{ProjectName}/releases/download/v";
|
||||
|
||||
private static readonly string _WindowsUpdateFile = "win-x64.zip";
|
||||
private static readonly string _LinuxUpdateFile = "linux-x64.zip";
|
||||
private static readonly string _MacOSUpdateFile = "osx-x64.zip";
|
||||
|
||||
private static readonly string _TempUpdateFolder = "temp";
|
||||
|
||||
private async Task<AppVersion> GetOnlineVersion()
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
var response = await client.GetAsync(_DefaultUpdateUrl);
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var version = Regex.Match(content, @"<title>.+?v(\d+\.\d+\.\d+.\d+).+?</title>").Groups[1].Value;
|
||||
|
||||
return new AppVersion(version);
|
||||
}
|
||||
|
||||
return AppVersion.CurrentAppVersion;
|
||||
}
|
||||
|
||||
public async Task<Update> CheckForUpdates()
|
||||
{
|
||||
var latestVersion = await GetOnlineVersion();
|
||||
if(latestVersion.IsNewerThan(AppVersion.CurrentAppVersion))
|
||||
{
|
||||
return new Update(AppVersion.CurrentAppVersion, latestVersion, _DefaultUpdateUrl, await GetUpdateNotes());
|
||||
}
|
||||
|
||||
return Update.None;
|
||||
}
|
||||
|
||||
private async Task<string> GetUpdateNotes()
|
||||
{
|
||||
HttpClient client = new HttpClient();
|
||||
var response = await client.GetAsync(_DefaultUpdateUrl);
|
||||
|
||||
if (!response.IsSuccessStatusCode)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
var content = await response.Content.ReadAsStringAsync();
|
||||
var markdownStart = content.IndexOf("<div data-pjax=\"true\" data-test-selector=\"body-content\"");
|
||||
if(markdownStart == -1)
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
markdownStart = content.IndexOf(">", markdownStart) + 1; // Move past the opening tag
|
||||
var markdownEnd = content.IndexOf("</div>", markdownStart);
|
||||
var markdown = content.Substring(markdownStart, markdownEnd - markdownStart).Trim();
|
||||
markdown = RemoveHtmlTags(markdown);
|
||||
|
||||
markdown = ApplyMarkdownFormatting(markdown);
|
||||
|
||||
return markdown;
|
||||
|
||||
return AppVersion.CurrentAppVersion;
|
||||
|
||||
var url = response.RequestMessage.RequestUri.ToString();
|
||||
var version = url.Split('/')[^1].Substring(1); // Remove the 'v' from the version number
|
||||
|
||||
return new AppVersion(version);
|
||||
}
|
||||
|
||||
private string GetDownloadUrl(AppVersion version)
|
||||
{
|
||||
string downloadUrl = _DefaultUpdateDownloadUrl;
|
||||
|
||||
downloadUrl += $"{version.ToShortString()}/";
|
||||
|
||||
if(OperatingSystem.IsWindows())
|
||||
downloadUrl += _WindowsUpdateFile;
|
||||
else if (OperatingSystem.IsLinux())
|
||||
downloadUrl += _LinuxUpdateFile;
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
downloadUrl += _MacOSUpdateFile;
|
||||
else
|
||||
throw new PlatformNotSupportedException("Unsupported operating system");
|
||||
|
||||
return downloadUrl;
|
||||
}
|
||||
|
||||
private string RemoveHtmlTags(string text)
|
||||
public async Task<Update?> PrepareUpdate()
|
||||
{
|
||||
return Regex.Replace(text, "<.*?>", "").Trim();
|
||||
AppVersion currentVersion = AppVersion.CurrentAppVersion;
|
||||
AppVersion newVersion = await GetOnlineVersion();
|
||||
|
||||
if(!newVersion.IsNewerThan(currentVersion))
|
||||
return null;
|
||||
|
||||
string downloadUrl = GetDownloadUrl(newVersion);
|
||||
Update update = new Update(currentVersion, newVersion, downloadUrl);
|
||||
|
||||
return update;
|
||||
}
|
||||
private string ApplyMarkdownFormatting(string markdown)
|
||||
|
||||
private void PrepareCurrentFolderForOverwrite()
|
||||
{
|
||||
// Apply markdown formatting
|
||||
markdown = markdown.Replace("**", "**"); // Bold
|
||||
markdown = markdown.Replace("*", "*"); // Italic
|
||||
markdown = markdown.Replace("`", "`"); // Inline code
|
||||
markdown = markdown.Replace("```", "```"); // Code block
|
||||
markdown = markdown.Replace(">", ">"); // Greater than symbol
|
||||
markdown = markdown.Replace("<", "<"); // Less than symbol
|
||||
markdown = markdown.Replace("&", "&"); // Ampersand
|
||||
markdown = markdown.Replace(""", "\""); // Double quote
|
||||
markdown = markdown.Replace("'", "'"); // Single quote
|
||||
markdown = markdown.Replace(" - ", "\n- "); // Convert bullet points to markdown list items
|
||||
List<string> files = new List<string>();
|
||||
files.AddRange(Directory.GetFiles("./"));
|
||||
|
||||
return markdown;
|
||||
foreach (var file in files)
|
||||
{
|
||||
File.Move(file, file + ".bak");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task CopyFolderContentOverCurrentFolder(string current, string otherFolder)
|
||||
{
|
||||
var files = Directory.GetFiles(otherFolder, "*.*", SearchOption.AllDirectories);
|
||||
foreach (var file in files)
|
||||
{
|
||||
string relativePath = file.Replace(otherFolder, "");
|
||||
string newPath = current + relativePath;
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(newPath));
|
||||
File.Copy(file, newPath);
|
||||
}
|
||||
}
|
||||
|
||||
public async Task SelfUpdate(Update update, IProgress<float> progress)
|
||||
{
|
||||
Directory.CreateDirectory(_TempUpdateFolder);
|
||||
|
||||
string tempFile = $"./{_TempUpdateFolder}/update.zip";
|
||||
string tempFolder = $"./{_TempUpdateFolder}/";
|
||||
|
||||
Directory.CreateDirectory(tempFolder);
|
||||
|
||||
await ServerCom.DownloadFileAsync(update.UpdateUrl, tempFile, progress);
|
||||
|
||||
await ArchiveManager.ExtractArchive(tempFile, tempFolder, progress, UnzipProgressType.PERCENTAGE_FROM_TOTAL_SIZE);
|
||||
|
||||
PrepareCurrentFolderForOverwrite();
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
tempFolder += _WindowsUpdateFile;
|
||||
else if (OperatingSystem.IsLinux())
|
||||
tempFolder += _LinuxUpdateFile;
|
||||
else if (OperatingSystem.IsMacOS())
|
||||
tempFolder += _MacOSUpdateFile;
|
||||
else throw new PlatformNotSupportedException();
|
||||
|
||||
await CopyFolderContentOverCurrentFolder("./", tempFolder.Substring(0, tempFolder.Length-4)); // Remove the .zip from the folder name
|
||||
|
||||
Process.Start("DiscordBot", "--update-cleanup");
|
||||
Environment.Exit(0);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -5,19 +5,15 @@ namespace DiscordBotCore.Updater.Application
|
||||
{
|
||||
public class Update
|
||||
{
|
||||
public readonly static Update None = new Update(AppVersion.CurrentAppVersion, AppVersion.CurrentAppVersion, string.Empty, string.Empty);
|
||||
|
||||
public AppVersion UpdateVersion { get; private set; }
|
||||
public AppVersion NewVersion { get; private set; }
|
||||
public AppVersion CurrentVersion { get; private set; }
|
||||
public string UpdateUrl { get; private set; }
|
||||
public string UpdateNotes { get; private set; }
|
||||
|
||||
public Update(AppVersion currentVersion, AppVersion updateVersion, string updateUrl, string updateNotes)
|
||||
public Update(AppVersion currentVersion, AppVersion updateVersion, string updateUrl)
|
||||
{
|
||||
UpdateVersion = updateVersion;
|
||||
NewVersion = updateVersion;
|
||||
CurrentVersion = currentVersion;
|
||||
UpdateUrl = updateUrl;
|
||||
UpdateNotes = updateNotes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user