Skip to content

Commit 8c8c5f3

Browse files
authored
2.3.1 (#193)
1 parent 322d24e commit 8c8c5f3

20 files changed

+123
-74
lines changed

onedrive-backup/CHANGELOG.md

+9
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,12 @@
1+
## v2.3.1 [March 19th 2024]
2+
### ❗Important
3+
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")
4+
### 🆕 Added
5+
* Added more persistent notifications for alerting on errors and improved overall behavior of persistant notifications
6+
### 🐞 Fixed
7+
* Issue downloading a backup from OneDrive to HomeAssistant
8+
* Minor UI fixes
9+
110
## v2.3 [Febuary 7th 2024]
211
### 🆕 Added
312
* Added ability to retain backups indefinitely

onedrive-backup/Contracts/AddonOptions.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ namespace hassio_onedrive_backup.Contracts
99
{
1010
public class AddonOptions : IEqualityComparer<AddonOptions>
1111
{
12-
public const string AddonVersion = "2.3";
12+
public const string AddonVersion = "2.3.1";
1313

1414
public event Action OnOptionsChanged;
1515

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
namespace onedrive_backup.Contracts
2+
{
3+
public static class PersistantNotificationIds
4+
{
5+
public static string OneDriveDelete = nameof(OneDriveDelete);
6+
7+
public static string LocalDelete = nameof(LocalDelete);
8+
9+
public static string BackupCreate = nameof(BackupCreate);
10+
11+
public static string BackupUpload = nameof(BackupUpload);
12+
13+
public static string Unexpected = nameof(Unexpected);
14+
}
15+
}

onedrive-backup/Graph/GraphHelper.cs

+40-11
Original file line numberDiff line numberDiff line change
@@ -171,10 +171,10 @@ public async Task<bool> UploadFileAsync(string filePath, DateTime date, string?
171171
});
172172

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

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

264-
var itemStream = await _userClient.Drives[drive.Id].Special["approot"].WithUrl(fileName).Content.GetAsync();
264+
var driveItem = await _userClient.Me.Drive.GetAsync();
265+
var appFolder = await _userClient.Drives[driveItem.Id].Special["approot"].GetAsync();
266+
var item = await _userClient.Drives[driveItem?.Id]
267+
.Items[appFolder.Id]
268+
.ItemWithPath(fileName)
269+
.GetAsync();
270+
271+
transferSpeedHelper.Start();
272+
var itemStream = await _userClient.Drives[driveItem?.Id]
273+
.Items[appFolder.Id]
274+
.ItemWithPath(fileName)
275+
.Content
276+
.GetAsync();
277+
278+
265279
var fileInfo = new FileInfo($"{LocalStorage.TempFolder}/{fileName}");
266280
using var fileStream = File.Create(fileInfo.FullName);
267281

268282
long totalBytesDownloaded = 0;
269283
int attempt = 1;
270-
while (totalBytesDownloaded < itemStream.Length)
284+
int bytesRead = 1;
285+
var lastShownPercentageHolder = new TransferProgressHolder();
286+
while (totalBytesDownloaded < item.Size && bytesRead > 0)
271287
{
272288
try
273289
{
274290
var buffer = new byte[ChunkSize];
275-
int bytesRead = await itemStream.ReadAsync(buffer, 0, ChunkSize);
291+
bytesRead = await itemStream.ReadAsync(buffer, 0, ChunkSize);
292+
await fileStream.WriteAsync(buffer, 0, bytesRead);
276293
totalBytesDownloaded += bytesRead;
277-
progressCallback?.Invoke((int)(totalBytesDownloaded * 100 / itemStream.Length));
294+
(double delay, double speed) = transferSpeedHelper.MarkAndCalcThrottle(totalBytesDownloaded);
295+
double percentage = Math.Round((totalBytesDownloaded / (double)item.Size), 2) * 100;
296+
if (percentage - lastShownPercentageHolder.Percentage >= 10 || percentage == 100)
297+
{
298+
_logger.LogVerbose($"Downloaded {percentage}%");
299+
lastShownPercentageHolder.Percentage = percentage;
300+
}
301+
if (percentage - lastShownPercentageHolder.Percentage >= 5 || percentage == 100)
302+
{
303+
progressCallback?.Invoke((int)percentage, (int)speed);
304+
}
278305
}
279306
catch (Exception ex)
280307
{
281308
if (attempt >= DownloadRetryCount)
282309
{
283310
_logger.LogError($"Failed downloading file {fileName}. {ex}", ex, _telemetryManager);
284-
progressCallback?.Invoke(null);
311+
progressCallback?.Invoke(0, 0);
312+
transferSpeedHelper.Reset();
285313
return null;
286314
}
287315

288316
await Task.Delay(5000);
289317
}
290318
}
291319

292-
progressCallback?.Invoke(null);
320+
progressCallback?.Invoke(0, 0);
321+
transferSpeedHelper.Reset();
293322
_logger.LogInfo($"{fileName} downloaded successfully");
294323
return fileInfo.FullName;
295324
}
@@ -358,7 +387,7 @@ private Task DeviceCodeBallBackPrompt(DeviceCodeInfo info, CancellationToken ct)
358387
return (url, code);
359388
}
360389

361-
private class UploadProgressHolder
390+
private class TransferProgressHolder
362391
{
363392
public double Percentage { get; set; } = 0;
364393
}

onedrive-backup/Graph/IGraphHelper.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public interface IGraphHelper
2424

2525
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);
2626

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

2929
Task<OneDriveFreeSpaceData> GetFreeSpaceInGB();
3030
}

onedrive-backup/Hass/BackupManager.cs

+17-14
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ public class BackupManager
2222
{
2323
private const int InstanceNameMaxLength = 20;
2424
private readonly HassOnedriveEntityState _hassEntityState;
25-
private readonly TransferSpeedHelper? _transferSpeedHelper;
2625
private readonly HassContext _hassContext;
2726
private readonly ConsoleLogger _logger;
2827
private readonly IDateTimeProvider _dateTimeProvider;
@@ -33,18 +32,18 @@ public class BackupManager
3332
private IGraphHelper _graphHelper;
3433
private IHassioClient _hassIoClient;
3534
private BitArray _allowedHours;
36-
protected bool _isExecuting = false;
35+
protected bool _isExecuting = false;
36+
3737

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

41-
public BackupManager(IServiceProvider serviceProvider, TransferSpeedHelper? transferSpeedHelper)
41+
public BackupManager(IServiceProvider serviceProvider)
4242
{
4343
_addonOptions = serviceProvider.GetService<AddonOptions>();
4444
_graphHelper = serviceProvider.GetService<IGraphHelper>();
4545
_hassIoClient = serviceProvider.GetService<IHassioClient>();
4646
_hassEntityState = serviceProvider.GetService<HassOnedriveEntityState>();
47-
_transferSpeedHelper = transferSpeedHelper;
4847
_hassContext = serviceProvider.GetService<HassContext>();
4948
_logger = serviceProvider.GetService<ConsoleLogger>();
5049
_dateTimeProvider = serviceProvider.GetService<IDateTimeProvider>();
@@ -185,7 +184,7 @@ public async Task PerformBackupsAsync()
185184
await _hassIoClient.PublishEventAsync(Events.OneDriveEvents.OneDriveBackupDeleteFailed);
186185
if (_addonOptions.NotifyOnError)
187186
{
188-
await _hassIoClient.SendPersistentNotificationAsync("Failed deleting old backup from OneDrive. Check Addon logs for more details");
187+
await _hassIoClient.SendPersistentNotificationAsync("Failed deleting old backup from OneDrive. Check Addon logs for more details", PersistantNotificationIds.OneDriveDelete);
189188
}
190189
}
191190
}
@@ -218,19 +217,19 @@ public async Task PerformBackupsAsync()
218217

219218
if (localBackupsToRemove.Any())
220219
{
221-
//_hassEntityState.State = HassOnedriveEntityState.BackupState.Syncing;
222-
//await _hassEntityState.UpdateBackupEntityInHass();
223220
await _hassEntityState.SyncStart();
224221
_logger.LogInfo($"Removing {numOfLocalBackupsToRemove} local backups");
225222
foreach (var localBackup in localBackupsToRemove)
226223
{
224+
_logger.LogVerbose($"Deleting local backup: {localBackup.Slug}");
227225
bool deleteSuccess = await _hassIoClient.DeleteBackupAsync(localBackup);
228226
if (deleteSuccess == false)
229227
{
228+
_logger.LogError($"Error removing local backup: {localBackup.Slug}");
230229
await _hassIoClient.PublishEventAsync(Events.OneDriveEvents.LocalBackupDeleteFailed);
231230
if (_addonOptions.NotifyOnError)
232231
{
233-
await _hassIoClient.SendPersistentNotificationAsync("Error Deleting Local Backup. Check Addon logs for more details");
232+
await _hassIoClient.SendPersistentNotificationAsync("Error Deleting Local Backup. Check Addon logs for more details", PersistantNotificationIds.LocalDelete);
234233
}
235234
}
236235
}
@@ -239,6 +238,10 @@ public async Task PerformBackupsAsync()
239238

240239
await _hassEntityState.SyncEnd();
241240
await RefreshBackupsAndUpdateHassEntity();
241+
if (_hassEntityState.State == HassOnedriveEntityState.BackupState.Stale )
242+
{
243+
244+
}
242245

243246
}
244247
finally
@@ -326,7 +329,7 @@ public async Task<bool> CreateLocalBackup()
326329
await _hassIoClient.PublishEventAsync(Events.OneDriveEvents.BackupCreateFailed);
327330
if (_addonOptions.NotifyOnError)
328331
{
329-
await _hassIoClient.SendPersistentNotificationAsync("Failed creating local backup. Check Addon logs for more details");
332+
await _hassIoClient.SendPersistentNotificationAsync("Failed creating local backup. Check Addon logs for more details", PersistantNotificationIds.BackupCreate);
330333
}
331334
}
332335
else
@@ -354,7 +357,7 @@ public async Task<bool> UploadLocalBackupToOneDrive(Backup backup, Action<int?,
354357
string? instanceSuffix = _addonOptions.InstanceName == null ? null : $".{_addonOptions.InstanceName.Substring(0, Math.Min(InstanceNameMaxLength, _addonOptions.InstanceName.Length))}";
355358
string destinationFileName = $"{backup.Name}{instanceSuffix}.tar";
356359
tempBackupFilePath = await _hassIoClient.DownloadBackupAsync(backup.Slug);
357-
var uploadSuccessful = await _graphHelper.UploadFileAsync(tempBackupFilePath, backup.Date, _addonOptions.InstanceName, _transferSpeedHelper, destinationFileName,
360+
var uploadSuccessful = await _graphHelper.UploadFileAsync(tempBackupFilePath, backup.Date, _addonOptions.InstanceName, new TransferSpeedHelper(null), destinationFileName,
358361
async (prog, speed) =>
359362
{
360363
if (updateHassEntityState)
@@ -373,7 +376,7 @@ public async Task<bool> UploadLocalBackupToOneDrive(Backup backup, Action<int?,
373376
await _hassIoClient.PublishEventAsync(Events.OneDriveEvents.BackupUploadFailed);
374377
if (_addonOptions.NotifyOnError)
375378
{
376-
await _hassIoClient.SendPersistentNotificationAsync("Failed uploading backup to onedrive. Check Addon logs for more details");
379+
await _hassIoClient.SendPersistentNotificationAsync("Failed uploading backup to onedrive. Check Addon logs for more details", PersistantNotificationIds.BackupUpload);
377380
}
378381
}
379382
}
@@ -394,21 +397,21 @@ public async Task<bool> UploadLocalBackupToOneDrive(Backup backup, Action<int?,
394397
return true;
395398
}
396399

397-
public async Task<bool> DownloadBackupFromOneDrive(OnedriveBackup onlineBackup, Action<int?>? progressCallback = null, bool updateHassEntityState = true)
400+
public async Task<bool> DownloadBackupFromOneDrive(OnedriveBackup onlineBackup, Action<int?, int?>? progressCallback = null, bool updateHassEntityState = true)
398401
{
399402
string? backupFile = null;
400403
try
401404
{
402405
_logger.LogInfo($"Downloading backup {onlineBackup.FileName}");
403-
backupFile = await _graphHelper.DownloadFileAsync(onlineBackup.FileName, async (prog) =>
406+
backupFile = await _graphHelper.DownloadFileAsync(onlineBackup.FileName, new TransferSpeedHelper(null), async (prog, speed) =>
404407
{
405408
if (updateHassEntityState)
406409
{
407410
_hassEntityState.DownloadPercentage = prog;
408411
await _hassEntityState.UpdateBackupEntityInHass();
409412
}
410413

411-
progressCallback?.Invoke(prog);
414+
progressCallback?.Invoke(prog, speed);
412415
});
413416

414417
if (backupFile == null)

onedrive-backup/Hass/HassioClient.cs

+9-4
Original file line numberDiff line numberDiff line change
@@ -166,18 +166,23 @@ public async Task<bool> UploadBackupAsync(string filePath)
166166
return true;
167167
}
168168

169-
public async Task SendPersistentNotificationAsync(string message)
169+
public async Task SendPersistentNotificationAsync(string message, string? notificationId = null)
170170
{
171171
try
172172
{
173-
Uri uri = new Uri(Hass_Base_Uri_Str + "/services/notify/persistent_notification");
173+
Uri uri = new Uri(Hass_Base_Uri_Str + "/services/persistent_notification/create");
174174
var payload = new
175175
{
176176
message = message,
177-
title = "hassio-onedrive-backup"
177+
title = "hassio-onedrive-backup",
178+
notification_id = notificationId
178179
};
179180

180-
string payloadStr = JsonConvert.SerializeObject(payload);
181+
string payloadStr = JsonConvert.SerializeObject(payload, new JsonSerializerSettings
182+
{
183+
NullValueHandling = NullValueHandling.Ignore
184+
});
185+
181186
await _httpClient.PostAsync(uri, new StringContent(payloadStr, Encoding.UTF8, "application/json"));
182187
}
183188
catch (Exception ex)

onedrive-backup/Hass/HassioClientMock.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public Task<string> DownloadBackupAsync(string backupSlug)
5757
string backupFile = $"./{backupSlug}.tar";
5858

5959
// 15MB File
60-
byte[] data = new byte[10 * 1024 * 1024];
60+
byte[] data = new byte[100 * 1024 * 1024];
6161
new Random().NextBytes(data);
6262
File.WriteAllBytes(backupFile, data);
6363
return Task.FromResult(backupFile);
@@ -105,7 +105,7 @@ public Task RestartSelf()
105105
return Task.CompletedTask;
106106
}
107107

108-
public Task SendPersistentNotificationAsync(string message)
108+
public Task SendPersistentNotificationAsync(string message, string? notificationId = null)
109109
{
110110
var payload = new
111111
{

onedrive-backup/Hass/IHassioClient.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ public interface IHassioClient
1010
{
1111
Task<List<Backup>> GetBackupsAsync(Predicate<Backup> filter);
1212

13-
Task SendPersistentNotificationAsync(string message);
13+
Task SendPersistentNotificationAsync(string message, string? notificationId = null);
1414

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

onedrive-backup/Orchestrator.cs

+6-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
using hassio_onedrive_backup.Hass;
44
using hassio_onedrive_backup.Sync;
55
using onedrive_backup;
6+
using onedrive_backup.Contracts;
67
using onedrive_backup.Graph;
78
using onedrive_backup.Telemetry;
89
using System.Collections;
@@ -34,7 +35,7 @@ public Orchestrator(IServiceProvider serviceProvider)
3435
_telemetryManager = serviceProvider.GetService<TelemetryManager>();
3536
_logger = serviceProvider.GetService<ConsoleLogger>();
3637
_allowedBackupHours = TimeRangeHelper.GetAllowedHours(_addonOptions.BackupAllowedHours);
37-
BackupManager = new BackupManager(_serviceProvider, new TransferSpeedHelper(null));
38+
BackupManager = new BackupManager(_serviceProvider);
3839
_addonOptions.OnOptionsChanged += OnOptionsChanged;
3940
}
4041

@@ -94,6 +95,10 @@ public async Task Start()
9495
catch (Exception ex)
9596
{
9697
_logger.LogError($"Unexpected error. {ex}", ex, _telemetryManager);
98+
if (_addonOptions.NotifyOnError)
99+
{
100+
await _hassIoClient.SendPersistentNotificationAsync("Unexpected Failure in OneDrive Backup Addon. Check Addon logs for more details", PersistantNotificationIds.Unexpected);
101+
}
97102
}
98103

99104
_logger.LogVerbose("Backup Interval Completed.");

onedrive-backup/Pages/Settings.razor

-1
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,6 @@
264264
{
265265
await JS.InvokeVoidAsync("addTooltips");
266266
await JS.InvokeVoidAsync("addToasts");
267-
await JS.InvokeVoidAsync("hideSettingsPopover");
268267
}
269268

270269
if (string.IsNullOrWhiteSpace(newOptions.SyncPaths.LastOrDefault()) == false || newOptions.SyncPaths.Any() == false)

0 commit comments

Comments
 (0)