Skip to content

Commit

Permalink
2.3.1 (#193)
Browse files Browse the repository at this point in the history
  • Loading branch information
lavinir authored Mar 19, 2024
1 parent 322d24e commit 8c8c5f3
Show file tree
Hide file tree
Showing 20 changed files with 123 additions and 74 deletions.
9 changes: 9 additions & 0 deletions onedrive-backup/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## v2.3.1 [March 19th 2024]
### ❗Important
Upgrade to Version 2.3 included updates to authentication libraries which caused some connection resets with OneDrive. Please make sure that you have a working connection post upgrade. For troubleshooting please refer to [this link]("https://github.com/lavinir/hassio-onedrive-backup/issues/174")
### 🆕 Added
* Added more persistent notifications for alerting on errors and improved overall behavior of persistant notifications
### 🐞 Fixed
* Issue downloading a backup from OneDrive to HomeAssistant
* Minor UI fixes

## v2.3 [Febuary 7th 2024]
### 🆕 Added
* Added ability to retain backups indefinitely
Expand Down
2 changes: 1 addition & 1 deletion onedrive-backup/Contracts/AddonOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ namespace hassio_onedrive_backup.Contracts
{
public class AddonOptions : IEqualityComparer<AddonOptions>

Check warning on line 10 in onedrive-backup/Contracts/AddonOptions.cs

View workflow job for this annotation

GitHub Actions / build

'AddonOptions' overrides Object.Equals(object o) but does not override Object.GetHashCode()
{
public const string AddonVersion = "2.3";
public const string AddonVersion = "2.3.1";

public event Action OnOptionsChanged;

Expand Down
15 changes: 15 additions & 0 deletions onedrive-backup/Contracts/PersistantNotificationIds.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
namespace onedrive_backup.Contracts
{
public static class PersistantNotificationIds
{
public static string OneDriveDelete = nameof(OneDriveDelete);

public static string LocalDelete = nameof(LocalDelete);

public static string BackupCreate = nameof(BackupCreate);

public static string BackupUpload = nameof(BackupUpload);

public static string Unexpected = nameof(Unexpected);
}
}
51 changes: 40 additions & 11 deletions onedrive-backup/Graph/GraphHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -171,10 +171,10 @@ public async Task<bool> UploadFileAsync(string filePath, DateTime date, string?
});

// todo: allow settings this in advanced configuration
int maxSlizeSize = ChunkSize;
int maxSliceSize = ChunkSize;
long totalFileLength = fileStream.Length;
var fileUploadTask = new LargeFileUploadTask<DriveItem>(uploadSession, fileStream, maxSlizeSize);
var lastShownPercentageHolder = new UploadProgressHolder();
var fileUploadTask = new LargeFileUploadTask<DriveItem>(uploadSession, fileStream, maxSliceSize);
var lastShownPercentageHolder = new TransferProgressHolder();
IProgress<long> progress = new Progress<long>(async prog =>
{
(double delayMS, double speed) = transferSpeedHelper.MarkAndCalcThrottle(prog);
Expand Down Expand Up @@ -257,39 +257,68 @@ public async Task<OneDriveFreeSpaceData> GetFreeSpaceInGB()
}
}

public async Task<string?> DownloadFileAsync(string fileName, Action<int?>? progressCallback)
public async Task<string?> DownloadFileAsync(string fileName, TransferSpeedHelper transferSpeedHelper, Action<int, int>? progressCallback)
{
var drive = await _userClient.Me.Drive.GetAsync();

var itemStream = await _userClient.Drives[drive.Id].Special["approot"].WithUrl(fileName).Content.GetAsync();
var driveItem = await _userClient.Me.Drive.GetAsync();
var appFolder = await _userClient.Drives[driveItem.Id].Special["approot"].GetAsync();
var item = await _userClient.Drives[driveItem?.Id]
.Items[appFolder.Id]
.ItemWithPath(fileName)
.GetAsync();

transferSpeedHelper.Start();
var itemStream = await _userClient.Drives[driveItem?.Id]
.Items[appFolder.Id]
.ItemWithPath(fileName)
.Content
.GetAsync();


var fileInfo = new FileInfo($"{LocalStorage.TempFolder}/{fileName}");
using var fileStream = File.Create(fileInfo.FullName);

long totalBytesDownloaded = 0;
int attempt = 1;
while (totalBytesDownloaded < itemStream.Length)
int bytesRead = 1;
var lastShownPercentageHolder = new TransferProgressHolder();
while (totalBytesDownloaded < item.Size && bytesRead > 0)
{
try
{
var buffer = new byte[ChunkSize];
int bytesRead = await itemStream.ReadAsync(buffer, 0, ChunkSize);
bytesRead = await itemStream.ReadAsync(buffer, 0, ChunkSize);
await fileStream.WriteAsync(buffer, 0, bytesRead);
totalBytesDownloaded += bytesRead;
progressCallback?.Invoke((int)(totalBytesDownloaded * 100 / itemStream.Length));
(double delay, double speed) = transferSpeedHelper.MarkAndCalcThrottle(totalBytesDownloaded);
double percentage = Math.Round((totalBytesDownloaded / (double)item.Size), 2) * 100;
if (percentage - lastShownPercentageHolder.Percentage >= 10 || percentage == 100)
{
_logger.LogVerbose($"Downloaded {percentage}%");
lastShownPercentageHolder.Percentage = percentage;
}
if (percentage - lastShownPercentageHolder.Percentage >= 5 || percentage == 100)
{
progressCallback?.Invoke((int)percentage, (int)speed);
}
}
catch (Exception ex)
{
if (attempt >= DownloadRetryCount)
{
_logger.LogError($"Failed downloading file {fileName}. {ex}", ex, _telemetryManager);
progressCallback?.Invoke(null);
progressCallback?.Invoke(0, 0);
transferSpeedHelper.Reset();
return null;
}

await Task.Delay(5000);
}
}

progressCallback?.Invoke(null);
progressCallback?.Invoke(0, 0);
transferSpeedHelper.Reset();
_logger.LogInfo($"{fileName} downloaded successfully");
return fileInfo.FullName;
}
Expand Down Expand Up @@ -358,7 +387,7 @@ private Task DeviceCodeBallBackPrompt(DeviceCodeInfo info, CancellationToken ct)
return (url, code);
}

private class UploadProgressHolder
private class TransferProgressHolder
{
public double Percentage { get; set; } = 0;
}
Expand Down
2 changes: 1 addition & 1 deletion onedrive-backup/Graph/IGraphHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public interface IGraphHelper

Task<bool> UploadFileAsync(string filePath, DateTime date, string? instanceName, TransferSpeedHelper transferSpeedHelper, string? destinationFileName = null, Action<int, int>? progressCallback = null, bool flatten = true, string description = null);

Check warning on line 25 in onedrive-backup/Graph/IGraphHelper.cs

View workflow job for this annotation

GitHub Actions / build

Cannot convert null literal to non-nullable reference type.

Task<string?> DownloadFileAsync(string fileName, Action<int?>? progressCallback);
Task<string?> DownloadFileAsync(string fileName, TransferSpeedHelper transferSpeedHelper, Action<int, int>? progressCallback);

Task<OneDriveFreeSpaceData> GetFreeSpaceInGB();
}
Expand Down
31 changes: 17 additions & 14 deletions onedrive-backup/Hass/BackupManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ public class BackupManager
{
private const int InstanceNameMaxLength = 20;
private readonly HassOnedriveEntityState _hassEntityState;
private readonly TransferSpeedHelper? _transferSpeedHelper;
private readonly HassContext _hassContext;
private readonly ConsoleLogger _logger;
private readonly IDateTimeProvider _dateTimeProvider;
Expand All @@ -33,18 +32,18 @@ public class BackupManager
private IGraphHelper _graphHelper;
private IHassioClient _hassIoClient;
private BitArray _allowedHours;
protected bool _isExecuting = false;
protected bool _isExecuting = false;


public List<Backup> LocalBackups { get; private set; }
public List<OnedriveBackup> OnlineBackups { get; private set; }

public BackupManager(IServiceProvider serviceProvider, TransferSpeedHelper? transferSpeedHelper)
public BackupManager(IServiceProvider serviceProvider)
{
_addonOptions = serviceProvider.GetService<AddonOptions>();
_graphHelper = serviceProvider.GetService<IGraphHelper>();
_hassIoClient = serviceProvider.GetService<IHassioClient>();
_hassEntityState = serviceProvider.GetService<HassOnedriveEntityState>();
_transferSpeedHelper = transferSpeedHelper;
_hassContext = serviceProvider.GetService<HassContext>();
_logger = serviceProvider.GetService<ConsoleLogger>();
_dateTimeProvider = serviceProvider.GetService<IDateTimeProvider>();
Expand Down Expand Up @@ -185,7 +184,7 @@ public async Task PerformBackupsAsync()
await _hassIoClient.PublishEventAsync(Events.OneDriveEvents.OneDriveBackupDeleteFailed);
if (_addonOptions.NotifyOnError)
{
await _hassIoClient.SendPersistentNotificationAsync("Failed deleting old backup from OneDrive. Check Addon logs for more details");
await _hassIoClient.SendPersistentNotificationAsync("Failed deleting old backup from OneDrive. Check Addon logs for more details", PersistantNotificationIds.OneDriveDelete);
}
}
}
Expand Down Expand Up @@ -218,19 +217,19 @@ public async Task PerformBackupsAsync()

if (localBackupsToRemove.Any())
{
//_hassEntityState.State = HassOnedriveEntityState.BackupState.Syncing;
//await _hassEntityState.UpdateBackupEntityInHass();
await _hassEntityState.SyncStart();
_logger.LogInfo($"Removing {numOfLocalBackupsToRemove} local backups");
foreach (var localBackup in localBackupsToRemove)
{
_logger.LogVerbose($"Deleting local backup: {localBackup.Slug}");
bool deleteSuccess = await _hassIoClient.DeleteBackupAsync(localBackup);
if (deleteSuccess == false)
{
_logger.LogError($"Error removing local backup: {localBackup.Slug}");
await _hassIoClient.PublishEventAsync(Events.OneDriveEvents.LocalBackupDeleteFailed);
if (_addonOptions.NotifyOnError)
{
await _hassIoClient.SendPersistentNotificationAsync("Error Deleting Local Backup. Check Addon logs for more details");
await _hassIoClient.SendPersistentNotificationAsync("Error Deleting Local Backup. Check Addon logs for more details", PersistantNotificationIds.LocalDelete);
}
}
}
Expand All @@ -239,6 +238,10 @@ public async Task PerformBackupsAsync()

await _hassEntityState.SyncEnd();
await RefreshBackupsAndUpdateHassEntity();
if (_hassEntityState.State == HassOnedriveEntityState.BackupState.Stale )
{

}

}
finally
Expand Down Expand Up @@ -326,7 +329,7 @@ public async Task<bool> CreateLocalBackup()
await _hassIoClient.PublishEventAsync(Events.OneDriveEvents.BackupCreateFailed);
if (_addonOptions.NotifyOnError)
{
await _hassIoClient.SendPersistentNotificationAsync("Failed creating local backup. Check Addon logs for more details");
await _hassIoClient.SendPersistentNotificationAsync("Failed creating local backup. Check Addon logs for more details", PersistantNotificationIds.BackupCreate);
}
}
else
Expand Down Expand Up @@ -354,7 +357,7 @@ public async Task<bool> UploadLocalBackupToOneDrive(Backup backup, Action<int?,
string? instanceSuffix = _addonOptions.InstanceName == null ? null : $".{_addonOptions.InstanceName.Substring(0, Math.Min(InstanceNameMaxLength, _addonOptions.InstanceName.Length))}";
string destinationFileName = $"{backup.Name}{instanceSuffix}.tar";
tempBackupFilePath = await _hassIoClient.DownloadBackupAsync(backup.Slug);
var uploadSuccessful = await _graphHelper.UploadFileAsync(tempBackupFilePath, backup.Date, _addonOptions.InstanceName, _transferSpeedHelper, destinationFileName,
var uploadSuccessful = await _graphHelper.UploadFileAsync(tempBackupFilePath, backup.Date, _addonOptions.InstanceName, new TransferSpeedHelper(null), destinationFileName,
async (prog, speed) =>
{
if (updateHassEntityState)
Expand All @@ -373,7 +376,7 @@ public async Task<bool> UploadLocalBackupToOneDrive(Backup backup, Action<int?,
await _hassIoClient.PublishEventAsync(Events.OneDriveEvents.BackupUploadFailed);
if (_addonOptions.NotifyOnError)
{
await _hassIoClient.SendPersistentNotificationAsync("Failed uploading backup to onedrive. Check Addon logs for more details");
await _hassIoClient.SendPersistentNotificationAsync("Failed uploading backup to onedrive. Check Addon logs for more details", PersistantNotificationIds.BackupUpload);
}
}
}
Expand All @@ -394,21 +397,21 @@ public async Task<bool> UploadLocalBackupToOneDrive(Backup backup, Action<int?,
return true;
}

public async Task<bool> DownloadBackupFromOneDrive(OnedriveBackup onlineBackup, Action<int?>? progressCallback = null, bool updateHassEntityState = true)
public async Task<bool> DownloadBackupFromOneDrive(OnedriveBackup onlineBackup, Action<int?, int?>? progressCallback = null, bool updateHassEntityState = true)
{
string? backupFile = null;
try
{
_logger.LogInfo($"Downloading backup {onlineBackup.FileName}");
backupFile = await _graphHelper.DownloadFileAsync(onlineBackup.FileName, async (prog) =>
backupFile = await _graphHelper.DownloadFileAsync(onlineBackup.FileName, new TransferSpeedHelper(null), async (prog, speed) =>
{
if (updateHassEntityState)
{
_hassEntityState.DownloadPercentage = prog;
await _hassEntityState.UpdateBackupEntityInHass();
}

progressCallback?.Invoke(prog);
progressCallback?.Invoke(prog, speed);
});

if (backupFile == null)
Expand Down
13 changes: 9 additions & 4 deletions onedrive-backup/Hass/HassioClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,18 +166,23 @@ public async Task<bool> UploadBackupAsync(string filePath)
return true;
}

public async Task SendPersistentNotificationAsync(string message)
public async Task SendPersistentNotificationAsync(string message, string? notificationId = null)
{
try
{
Uri uri = new Uri(Hass_Base_Uri_Str + "/services/notify/persistent_notification");
Uri uri = new Uri(Hass_Base_Uri_Str + "/services/persistent_notification/create");
var payload = new
{
message = message,
title = "hassio-onedrive-backup"
title = "hassio-onedrive-backup",
notification_id = notificationId
};

string payloadStr = JsonConvert.SerializeObject(payload);
string payloadStr = JsonConvert.SerializeObject(payload, new JsonSerializerSettings
{
NullValueHandling = NullValueHandling.Ignore
});

await _httpClient.PostAsync(uri, new StringContent(payloadStr, Encoding.UTF8, "application/json"));
}
catch (Exception ex)
Expand Down
4 changes: 2 additions & 2 deletions onedrive-backup/Hass/HassioClientMock.cs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ public Task<string> DownloadBackupAsync(string backupSlug)
string backupFile = $"./{backupSlug}.tar";

// 15MB File
byte[] data = new byte[10 * 1024 * 1024];
byte[] data = new byte[100 * 1024 * 1024];
new Random().NextBytes(data);
File.WriteAllBytes(backupFile, data);
return Task.FromResult(backupFile);
Expand Down Expand Up @@ -105,7 +105,7 @@ public Task RestartSelf()
return Task.CompletedTask;
}

public Task SendPersistentNotificationAsync(string message)
public Task SendPersistentNotificationAsync(string message, string? notificationId = null)
{
var payload = new
{
Expand Down
2 changes: 1 addition & 1 deletion onedrive-backup/Hass/IHassioClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ public interface IHassioClient
{
Task<List<Backup>> GetBackupsAsync(Predicate<Backup> filter);

Task SendPersistentNotificationAsync(string message);
Task SendPersistentNotificationAsync(string message, string? notificationId = null);

Task<bool> CreateBackupAsync(string backupName, DateTime timeStamp, bool appendTimestamp = true, bool compressed = true, string? password = null, IEnumerable<string>? folders = null, IEnumerable<string>? addons = null);

Expand Down
7 changes: 6 additions & 1 deletion onedrive-backup/Orchestrator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
using hassio_onedrive_backup.Hass;
using hassio_onedrive_backup.Sync;
using onedrive_backup;
using onedrive_backup.Contracts;
using onedrive_backup.Graph;
using onedrive_backup.Telemetry;
using System.Collections;
Expand Down Expand Up @@ -34,7 +35,7 @@ public Orchestrator(IServiceProvider serviceProvider)
_telemetryManager = serviceProvider.GetService<TelemetryManager>();
_logger = serviceProvider.GetService<ConsoleLogger>();
_allowedBackupHours = TimeRangeHelper.GetAllowedHours(_addonOptions.BackupAllowedHours);
BackupManager = new BackupManager(_serviceProvider, new TransferSpeedHelper(null));
BackupManager = new BackupManager(_serviceProvider);
_addonOptions.OnOptionsChanged += OnOptionsChanged;
}

Expand Down Expand Up @@ -94,6 +95,10 @@ public async Task Start()
catch (Exception ex)
{
_logger.LogError($"Unexpected error. {ex}", ex, _telemetryManager);
if (_addonOptions.NotifyOnError)
{
await _hassIoClient.SendPersistentNotificationAsync("Unexpected Failure in OneDrive Backup Addon. Check Addon logs for more details", PersistantNotificationIds.Unexpected);
}
}

_logger.LogVerbose("Backup Interval Completed.");
Expand Down
1 change: 0 additions & 1 deletion onedrive-backup/Pages/Settings.razor
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,6 @@
{
await JS.InvokeVoidAsync("addTooltips");
await JS.InvokeVoidAsync("addToasts");
await JS.InvokeVoidAsync("hideSettingsPopover");
}

if (string.IsNullOrWhiteSpace(newOptions.SyncPaths.LastOrDefault()) == false || newOptions.SyncPaths.Any() == false)
Expand Down
Loading

0 comments on commit 8c8c5f3

Please sign in to comment.