Updater/Updater/NewUpdater.cs
2024-11-15 00:44:25 -05:00

401 lines
16 KiB
C#

using System.ComponentModel;
using System.Diagnostics;
using System.Net;
using System.Reflection;
using GraphicsManager;
using GraphicsManager.Enums;
using GraphicsManager.Objects;
using GraphicsManager.Objects.Core;
using OpenTK.Mathematics;
using OpenTK.Windowing.Desktop;
namespace Updater;
public class NewUpdater : FPSWindow
{
private readonly ConfigFile cf;
private ProgressBar<ulong> TotalProgress;
private Argumets Argumets;
private List<Tuple<ProgressBar<ulong>, Label, int>> ProgressThreads = new();
private readonly BackgroundWorker Download = new();
private Label? Total_Downloaded, Transfer_Speed;
private readonly System.Timers.Timer Speed;
private List<double> speeds = new();
public NewUpdater(NativeWindowSettings nws, GameWindowSettings gws, Argumets args)
:base(nws, gws)
{
ShowMissingChar = false;
LogFrames = false;
Speed = new()
{
Interval = 500
};
Speed.Elapsed += Speed_Elapsed;
CanControleUpdate = false;
//small = (uint)Math.Round(0.0656167979002625 * StartGUI.Height, 0);
//RenderObjects.Add(Total_Downloaded = new RenderText("Download Amount", "OpenSans-Regular", small, -0.9381188f, 0.149797574f, 1.0f, new Vector2(1f, 0f), new Vector4(cf.Colors.Text.R, cf.Colors.Text.G, cf.Colors.Text.B, cf.Colors.Text.A)));
//small = (uint)Math.Round(0.078740157480315 * StartGUI.Height, 0);
//RenderObjects.Add(Transfer_Speed = new RenderText("Download Speed", "OpenSans-Regular", small, -0.9381188f, -0.05263158f, 1.2f, new Vector2(1f, 0f), new Vector4(cf.Colors.Text.R, cf.Colors.Text.G, cf.Colors.Text.B, cf.Colors.Text.A)));
FontFamily r = FontFamily.LoadFontFamily(Tools.GetResourceStream(Assembly.GetExecutingAssembly(), "Updater.Resource.OpenSans.zip"), "OpenSans");
FontInteraction fi = FontInteraction.Load(r);
cf = Config.GetConfig();
Size = new(cf.Scale(Size.X), cf.Scale(Size.Y));
Argumets = args;
int WallDistance = cf.Scale(15);
BackgroundColor = cf.Colors.Background.ToColor4();
Texture ProgressbarTexture = TextureManager.AddTexture(File.OpenRead("/home/jacob/Pictures/Progress.png"));
Controls.Add(TotalProgress = new(ProgressbarTexture)
{
Location = new(WallDistance, cf.Scale(70)),
Size = new(Size.X - WallDistance - WallDistance, cf.Scale(20)),
BackgroundColor = cf.Colors.Progress_bars.Backcolor.ToColor4(),
ProgressColor = cf.Colors.Progress_bars.Fillcolor.ToColor4(),
ProgressValue = 5,
ProgressGap = new(cf.Scale(3)),
Shader = Rectangle.DefaultAlphaShader[Context],
TextureDisplay = TextureDisplay.ProgressHorizontalCenter,
UpdateOnDraw = true,
InnerShader = Rectangle.DefaultAlphaShader[Context]
});
fi.PixelHeight = (uint)WallDistance;
TotalProgress.Controls.Add(Total_Downloaded = new(fi)
{
Color = Color4.Black,
Text = "Downloading ...."
});
Total_Downloaded.Location = new(cf.Scale(5), (TotalProgress.Size.Y - Total_Downloaded.Size.Y) / 2);
Controls.Add(Transfer_Speed = new(fi)
{
Text = "abcdefghijklmnopqrstuvwxyz",
Location = new(WallDistance + Total_Downloaded.Location.X, cf.Scale(5))
});
int gap = cf.Scale(10);
for (int i = 0; i < cf.Format.DownloadThreads; i++)
{
ProgressBar<ulong> temp;
Size = new(Size.X, Size.Y + gap + TotalProgress.Size.Y);
Label l = new(fi)
{
Color = Color4.Black,
Text = "Downloading ...."
};
l.Location = new(Total_Downloaded.Location.X, (TotalProgress.Size.Y - l.Size.Y) / 2);
Controls.Add(temp = new(ProgressbarTexture)
{
Location = new(WallDistance, cf.Scale(70) + (TotalProgress.Size.Y * (i + 1)) + (gap * (i + 1))),
Size = TotalProgress.Size,
BackgroundColor = TotalProgress.BackgroundColor,
ProgressColor = TotalProgress.ProgressColor,
ProgressValue = 100,
ProgressGap = TotalProgress.ProgressGap,
Shader = TotalProgress.Shader,
TextureDisplay = TotalProgress.TextureDisplay,
UpdateOnDraw = true,
InnerShader = TotalProgress.InnerShader
});
temp.Controls.Add(l);
ProgressThreads.Add(new(temp,l, i));
}
Download.DoWork += Download_DoWork;
Download.RunWorkerCompleted += Download_RunWorkerCompleted;
Download.WorkerReportsProgress = true;
Invoke(Download.RunWorkerAsync);
Speed.Start();
}
private ulong last;
private string end = "";
private void Speed_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
{
ulong BytesPertenthSec;
if (last > TotalProgress.ProgressValue) BytesPertenthSec= 0;
else BytesPertenthSec= (TotalProgress.ProgressValue) - last;
last = TotalProgress.ProgressValue;
speeds.Add(BytesPertenthSec * 2);
if (speeds.Count > 25) speeds.RemoveAt(0);
if (Transfer_Speed is not null && speeds.Average() != 0)
{
Transfer_Speed.Text = Download_Speed_Neat(speeds.Average());
Set_Downloaded_Amount_Neat();
}
}
private void Download_DoWork(object? sender, DoWorkEventArgs e)
{
try
{
void TryDeleteDir(string? dir)
{
if (string.IsNullOrEmpty(dir) || string.IsNullOrWhiteSpace(dir)) return;
try
{
if (Directory.Exists(dir)) Directory.Delete(dir, true);
}
catch
{
DirectoryInfo dirInfo = new(dir);
foreach (var file in dirInfo.GetFiles())
{
try
{
file.Delete();
}
catch
{
// ignored
}
}
foreach (var subdir in dirInfo.GetDirectories())
{
TryDeleteDir(subdir.FullName);
}
}
}
TryDeleteDir(Argumets.LocalDirectory);
Directory.CreateDirectory(Argumets.LocalDirectory);
try
{
HttpClient client = new();
Task<string> files_pre = client.GetStringAsync($"https://{Handler.Domain}/Updater/Files?directory={Argumets.RemoteDirectory}{Argumets.UriBranch}{Argumets.UriSeflContaind}{Argumets.UriPlatform}{Argumets.UriVersion}");
Task<string> max_pre = client.GetStringAsync(
$"https://{Handler.Domain}/Updater/GetSize?directory={Argumets.RemoteDirectory}{Argumets.UriBranch}{Argumets.UriSeflContaind}{Argumets.UriPlatform}{Argumets.UriVersion}");
max_pre.Wait();
TotalProgress.MaxProgressValue = ulong.Parse(max_pre.Result);
end = Downloaded_Amount_Neat(TotalProgress.MaxProgressValue);
files_pre.Wait();
string[] files = files_pre.Result.Split('\n');
Queue<int> IndexesWaiting = new();
for (int i = 0; i < cf.Format.DownloadThreads; i++)
{
IndexesWaiting.Enqueue(i);
}
_ = Parallel.ForEach(files, new ParallelOptions() { MaxDegreeOfParallelism = cf.Format.DownloadThreads },
file =>
{
try
{
int v;
lock (IndexesWaiting)
{
v = IndexesWaiting.Dequeue();
}
Tuple<ProgressBar<ulong>, Label, int> pb = ProgressThreads[v];
StartDownloadForFile(file, pb.Item1, pb.Item2).Wait();
IndexesWaiting.Enqueue(v);
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
);
}
catch (Exception ex)
{
StackTrace st = new(ex, true);
StackFrame? frame = st.GetFrame(0);
if (frame is null) return;
int line = frame.GetFileLineNumber();
string msg = $"Error in Updater.exe in function Download_DoWork on line '{line}' through error '{ex.Message}'\nERROR:\n'{ex}' FRAM:\n '{frame}'";
MessageBox.Show(ex.ToString());
_ = new HttpClient().PostAsync($"https://{Handler.Domain}/Updater/Error/updater", new StringContent(msg));
}
}
catch (Exception exception)
{
Console.WriteLine(exception);
throw;
}
}
private async Task StartDownloadForFile(string file, ProgressBar<ulong> pb, Label pbLabel)
{
if (string.IsNullOrWhiteSpace(file)) return;
string[] temp = file.Split('/');
if (file.Contains('/'))
{
string cur = "";
for (int i = 0; i < temp.Length - 1; i++)
{
cur = Path.Join(cur, temp[i]);
if (!Directory.Exists(Path.Join(Argumets.LocalDirectory, cur)))
Directory.CreateDirectory(Path.Join(Argumets.LocalDirectory, cur));
}
}
using HttpClient client = new();
string max = await client.GetStringAsync($"https://{Handler.Domain}/Updater/GetFileSize?directory={Argumets.RemoteDirectory}{Argumets.UriBranch}{Argumets.UriVersion}{Argumets.UriSeflContaind}{Argumets.UriPlatform}&file={file}");
Invoke(() =>
{
pb.ProgressValue = 0;
pb.MaxProgressValue = ulong.Parse(max);
string s = $"Downloading {temp[^1]}";
try
{
pbLabel.Text = s;
}
catch (Exception e)
{
Console.WriteLine(e);
}
});
await DownloadFileAsync(pb,
$"https://{Handler.Domain}/Updater/GetFile?directory={Argumets.RemoteDirectory}{Argumets.UriBranch}{Argumets.UriVersion}{Argumets.UriSeflContaind}{Argumets.UriPlatform}&file={file}",
file.Replace("/", Handler.Slash));
}
private async Task DownloadFileAsync(ProgressBar<ulong> progressBar, string url, string destinationPath)
{
using (HttpClient client = new HttpClient())
using (HttpResponseMessage response = await client.GetAsync(url, HttpCompletionOption.ResponseHeadersRead))
{
response.EnsureSuccessStatusCode();
using (var contentStream = await response.Content.ReadAsStreamAsync())
using (var fileStream = new FileStream(Path.Join(Argumets.LocalDirectory, destinationPath), FileMode.Create, FileAccess.Write, FileShare.None, 8192, true))
{
var buffer = new byte[8192];
long totalRead = 0;
int bytesRead;
while ((bytesRead = await contentStream.ReadAsync(buffer, 0, buffer.Length)) > 0)
{
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalRead += bytesRead;
TotalProgress.ProgressValue += (ulong)bytesRead;
progressBar.ProgressValue = (ulong)totalRead;
}
}
}
}
private void Download_RunWorkerCompleted(object? sender, RunWorkerCompletedEventArgs e)
{
try
{
Invoke(Close);
}
catch (Exception exception)
{
Console.WriteLine(exception);
}
}
#region Neat
private string Download_Speed_Neat(double Number)
{
ConfigFileSize cfs = cf.Format.DownloadSpeed;
string Size = SizeName(Number, cfs);
int bytes = 1024;
if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MebiByte) bytes = 1000;
int Exponet;
if (Number / bytes >= 1)
if (Number / Math.Pow(bytes, 2) >= 1)
if (Number / Math.Pow(bytes, 3) >= 1) Exponet = 3;
else Exponet = 2;
else Exponet = 1;
else Exponet = 0;
if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MegaBit) Number *= 8;
Number = Math.Round(Number / Math.Pow(bytes, Exponet), 2, MidpointRounding.ToEven);
if (!Number.ToString().Contains('.'))
{
return $"{Number}.00{Size}/s";
}
else
{
if (Number.ToString().Remove(0, Number.ToString().IndexOf('.')).Length == 1)
{
return $"{Number}0{Size}/s";
}
else
{
return $"{Number}{Size}/s";
}
}
}
private void Set_Downloaded_Amount_Neat()
{
Total_Downloaded!.Text = $"Downloaded {Downloaded_Amount_Neat(TotalProgress.ProgressValue)} of {end}";
}
private string Downloaded_Amount_Neat(double Number)
{
int Exponet = 0;
ConfigFileSize cfs = cf.Format.DownloadAmount;
int bytes = 1024;
if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MebiByte) bytes = 1000;
string Size = SizeName(Number, cfs);
if (Size.ToLower().StartsWith('g')) Exponet = 3;
else if (Size.ToLower().StartsWith('m')) Exponet = 2;
else if (Size.ToLower().StartsWith('k')) Exponet = 1;
Number = Math.Round(Number / Math.Pow(bytes, Exponet), 2, MidpointRounding.ToEven);
if (cfs == ConfigFileSize.MebiBit || cfs == ConfigFileSize.MegaBit) Number *= 8;
string text = "";
if (!Number.ToString().Contains('.'))
{
text = $"{Number}.00{Size}{text}";
}
else
{
text = Number.ToString().Remove(0, Number.ToString().IndexOf('.')).Length != 1 ? $"{Number}{Size}{text}" : $"{Number}0{Size}{text}";
}
return text;
}
private static string SizeName(double Number, ConfigFileSize format)
{
string Size;
switch (format)
{
default:
case ConfigFileSize.MegaByte:
if (Number / 1000 >= 1)
if (Number / Math.Pow(1000, 2) >= 1)
if (Number / Math.Pow(1000, 3) >= 1) Size = "GB";
else Size = "MB";
else Size = "KB";
else Size = "B";
break;
case ConfigFileSize.MebiByte:
if (Number / 1024 >= 1)
if (Number / Math.Pow(1024, 2) >= 1)
if (Number / Math.Pow(1024, 3) >= 1) Size = "GiB";
else Size = "MiB";
else Size = "KiB";
else Size = "B";
break;
case ConfigFileSize.MegaBit:
Number *= 8;
if (Number / 1000 >= 1)
if (Number / Math.Pow(1000, 2) >= 1)
if (Number / Math.Pow(1000, 3) >= 1) Size = "Gb";
else Size = "Mb";
else Size = "Kb";
else Size = "b";
break;
case ConfigFileSize.MebiBit:
Number *= 8;
if (Number / 1024 >= 1)
if (Number / Math.Pow(1024, 2) >= 1)
if (Number / Math.Pow(1024, 3) >= 1) Size = "Gib";
else Size = "Mib";
else Size = "Kib";
else Size = "b";
break;
}
return Size;
}
#endregion
}