177 lines
5.6 KiB
C#
177 lines
5.6 KiB
C#
// Copyright (c) 2012-2024 Wojciech Figat. All rights reserved.
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
|
|
namespace Flax.Deps
|
|
{
|
|
/// <summary>
|
|
/// Class to display download progress
|
|
/// </summary>
|
|
public class ProgressDisplay : IDisposable
|
|
{
|
|
/// <summary>
|
|
/// Current progress
|
|
/// </summary>
|
|
private long _progress;
|
|
|
|
/// <summary>
|
|
/// Current display thread
|
|
/// </summary>
|
|
private readonly Thread _asyncDisplayThread;
|
|
|
|
/// <summary>
|
|
/// Progress display console position
|
|
/// </summary>
|
|
private readonly int _cursorPos;
|
|
|
|
/// <summary>
|
|
/// Queue of diffs from progress
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Queue last second of data
|
|
/// </remarks>
|
|
private readonly Queue<long> _progressQueue = new Queue<long>();
|
|
|
|
/// <summary>
|
|
/// Last progress to calculate progress diff
|
|
/// </summary>
|
|
private long _lastProgress;
|
|
|
|
/// <summary>
|
|
/// Should thread be alive
|
|
/// </summary>
|
|
private bool _isAlive = true;
|
|
|
|
/// <summary>
|
|
/// Total file size in bytes
|
|
/// </summary>
|
|
public long TotalFileSizeBytes { get; private set; }
|
|
|
|
/// <summary>
|
|
/// Current progress of task
|
|
/// </summary>
|
|
public long Progress
|
|
{
|
|
get => _progress;
|
|
set
|
|
{
|
|
if (value < _progress)
|
|
{
|
|
throw new Exception("Value cannot be smaller then current progress.");
|
|
}
|
|
|
|
_progress = value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Gets a value indicating whether can use system console for progress reporting.
|
|
/// </summary>
|
|
public static bool CanUseConsole
|
|
{
|
|
get
|
|
{
|
|
return false;
|
|
/*
|
|
try
|
|
{
|
|
// App crashes on Azure DevOps with exception:
|
|
// The handle is invalid.
|
|
// at
|
|
// at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
|
|
// at System.Console.GetBufferInfo(Boolean throwOnNoConsole, Boolean & succeeded)
|
|
// at Flax.Deps.ProgressDisplay..ctor(Int64 totalFileSizeBytes)
|
|
int a = Console.CursorTop;
|
|
Console.SetCursorPosition(0, a + 1);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Console.WriteLine("No ProgressDisplay support.");
|
|
Console.WriteLine(ex.Message);
|
|
Console.WriteLine();
|
|
Console.WriteLine(ex.StackTrace);
|
|
Console.WriteLine();
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
*/
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Initializes a new instance of the <see cref="ProgressDisplay"/> class.
|
|
/// </summary>
|
|
/// <param name="totalFileSizeBytes">The total file size bytes.</param>
|
|
public ProgressDisplay(long totalFileSizeBytes)
|
|
{
|
|
TotalFileSizeBytes = totalFileSizeBytes;
|
|
_cursorPos = Console.CursorTop;
|
|
Console.SetCursorPosition(0, _cursorPos + 1);
|
|
_asyncDisplayThread = new Thread(Display);
|
|
_asyncDisplayThread.Start();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates the progress.
|
|
/// </summary>
|
|
/// <param name="progress">The progress.</param>
|
|
/// <param name="totalLength">The total length.</param>
|
|
public void Update(long progress, long totalLength)
|
|
{
|
|
TotalFileSizeBytes = totalLength <= 0 ? progress : totalLength;
|
|
_progress = progress;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Updates console text with current progress.
|
|
/// </summary>
|
|
private void Display()
|
|
{
|
|
lock (_asyncDisplayThread)
|
|
{
|
|
while (_isAlive)
|
|
{
|
|
// Set queue progress
|
|
_progressQueue.Enqueue(Progress - _lastProgress);
|
|
|
|
// Remember last cursor position
|
|
var cursorPosTop = Console.CursorTop;
|
|
var cursorPosLeft = Console.CursorLeft;
|
|
|
|
// Set cursor position at progress display location
|
|
Console.SetCursorPosition(0, _cursorPos);
|
|
var display = $"Downloading: {(Progress / (1024 * 1024f)):0.00} MB / {(TotalFileSizeBytes / (1024 * 1024f)):0.00} - {_progressQueue.Sum() / (1024 * 1024f):0.00} MB/s";
|
|
// TODO add blank space fillings at the end of line if previous line was longer
|
|
Console.WriteLine(display);
|
|
|
|
// Set back previous position
|
|
Console.SetCursorPosition(cursorPosLeft, cursorPosTop);
|
|
|
|
// Remove old entries from queue
|
|
if (_progressQueue.Count > 10)
|
|
{
|
|
_progressQueue.Dequeue();
|
|
}
|
|
|
|
_lastProgress = Progress;
|
|
|
|
// Wait 1/10 of second
|
|
Thread.Sleep(100);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
|
|
/// </summary>
|
|
public void Dispose()
|
|
{
|
|
_isAlive = false;
|
|
}
|
|
}
|
|
}
|