d70d81ebdf
OneDrive Backup
226 lines
8.9 KiB
C#
226 lines
8.9 KiB
C#
using hassio_onedrive_backup.Contracts;
|
|
using hassio_onedrive_backup.Hass.Events;
|
|
using hassio_onedrive_backup.Storage;
|
|
using Newtonsoft.Json;
|
|
using onedrive_backup.Contracts;
|
|
using System.Globalization;
|
|
using System.Net.Http.Headers;
|
|
using System.Text;
|
|
using static hassio_onedrive_backup.Contracts.HassAddonsResponse;
|
|
using static hassio_onedrive_backup.Contracts.HassBackupsResponse;
|
|
|
|
namespace hassio_onedrive_backup.Hass
|
|
{
|
|
internal class HassioClient : IHassioClient
|
|
{
|
|
private const string Supervisor_Base_Uri_Str = "http://supervisor";
|
|
private const string Hass_Base_Uri_Str = "http://supervisor/core/api";
|
|
private readonly HttpClient _httpClient;
|
|
|
|
public HassioClient(string token, int hassioTimeout)
|
|
{
|
|
_httpClient = new HttpClient();
|
|
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);
|
|
_httpClient.Timeout = TimeSpan.FromMinutes(hassioTimeout);
|
|
}
|
|
|
|
public async Task<bool> DeleteBackupAsync(Backup backup)
|
|
{
|
|
try
|
|
{
|
|
Uri uri = new Uri(Supervisor_Base_Uri_Str + $"/backups/{backup.Slug}");
|
|
await _httpClient.DeleteAsync(uri);
|
|
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConsoleLogger.LogError($"Error deleting backup {backup.Slug}. {ex}");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public async Task<List<Backup>> GetBackupsAsync(Predicate<Backup> filter)
|
|
{
|
|
Uri uri = new Uri(Supervisor_Base_Uri_Str + "/backups");
|
|
var response = await GetJsonResponseAsync<HassBackupsResponse>(uri);
|
|
if (response.Result.Equals("ok", StringComparison.OrdinalIgnoreCase) == false)
|
|
{
|
|
throw new InvalidOperationException($"Failed getting Backups from Supervisor. Result: {response.Result}");
|
|
}
|
|
|
|
var backups = response.DataProperty.Backups;
|
|
|
|
return filter != null ? backups.Where(backup => filter(backup)).ToList() : backups.ToList();
|
|
}
|
|
|
|
public async Task<bool> CreateBackupAsync(string backupName, bool appendTimestamp = true, bool compressed = true, string? password = null, IEnumerable<string>? folders = null, IEnumerable<string>? addons = null)
|
|
{
|
|
DateTime timeStamp = DateTimeHelper.Instance!.Now;
|
|
const string dt_format = "yyyy-MM-dd-HH-mm";
|
|
|
|
string? payloadStr;
|
|
Uri? uri;
|
|
|
|
string finalBackupName = appendTimestamp ? $"{backupName}_{timeStamp.ToString(dt_format, CultureInfo.CurrentCulture)}" : backupName;
|
|
|
|
// Full Backup
|
|
if (folders == null && addons == null)
|
|
{
|
|
uri = new Uri(Supervisor_Base_Uri_Str + "/backups/new/full");
|
|
var fullPayload = new
|
|
{
|
|
name = finalBackupName,
|
|
compressed = compressed,
|
|
password = password
|
|
};
|
|
|
|
payloadStr = JsonConvert.SerializeObject(fullPayload, new JsonSerializerSettings
|
|
{
|
|
NullValueHandling = NullValueHandling.Ignore
|
|
});
|
|
|
|
ConsoleLogger.LogInfo("Starting full local backup");
|
|
}
|
|
// Partial Backup
|
|
else
|
|
{
|
|
uri = new Uri(Supervisor_Base_Uri_Str + "/backups/new/partial");
|
|
var partialPayload = new
|
|
{
|
|
name = finalBackupName,
|
|
compressed = compressed,
|
|
password = password,
|
|
homeassistant = true,
|
|
addons = addons,
|
|
folders = folders
|
|
};
|
|
|
|
payloadStr = JsonConvert.SerializeObject(partialPayload, new JsonSerializerSettings
|
|
{
|
|
NullValueHandling = NullValueHandling.Ignore
|
|
});
|
|
|
|
ConsoleLogger.LogInfo("Starting partial local backup");
|
|
}
|
|
|
|
try
|
|
{
|
|
await _httpClient.PostAsync(uri, new StringContent(payloadStr, Encoding.UTF8, "application/json"));
|
|
ConsoleLogger.LogInfo("Backup complete");
|
|
}
|
|
catch (TaskCanceledException tce)
|
|
{
|
|
if (tce.InnerException is TimeoutException)
|
|
{
|
|
ConsoleLogger.LogError($"Backup request timed out. {tce}");
|
|
ConsoleLogger.LogError($"Increase the timeout value in configuration");
|
|
return false;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConsoleLogger.LogError($"Failed creating new backup. {ex}");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public async Task<bool> UploadBackupAsync(string filePath)
|
|
{
|
|
try
|
|
{
|
|
Uri uri = new Uri(Supervisor_Base_Uri_Str + "/backups/new/upload");
|
|
using var multiPartFormContent = new MultipartFormDataContent();
|
|
var fsContent = new StreamContent(System.IO.File.OpenRead(filePath));
|
|
multiPartFormContent.Add(fsContent, name: "file", fileName: filePath);
|
|
var response = await _httpClient.PostAsync(uri, multiPartFormContent);
|
|
response.EnsureSuccessStatusCode();
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConsoleLogger.LogError($"Error uploading backup to Home Assistant. {ex}");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public async Task SendPersistentNotificationAsync(string message)
|
|
{
|
|
try
|
|
{
|
|
Uri uri = new Uri(Hass_Base_Uri_Str + "/services/notify/persistent_notification");
|
|
var payload = new
|
|
{
|
|
message = message,
|
|
title = "hassio-onedrive-backup"
|
|
};
|
|
|
|
string payloadStr = JsonConvert.SerializeObject(payload);
|
|
await _httpClient.PostAsync(uri, new StringContent(payloadStr, Encoding.UTF8, "application/json"));
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
ConsoleLogger.LogError($"Failed sending persistent notification. {ex}");
|
|
}
|
|
}
|
|
|
|
public async Task<List<Addon>> GetAddonsAsync()
|
|
{
|
|
Uri uri = new Uri(Supervisor_Base_Uri_Str + "/addons");
|
|
var response = await GetJsonResponseAsync<HassAddonsResponse>(uri);
|
|
var ret = response.DataProperty.Addons.ToList();
|
|
return ret;
|
|
}
|
|
|
|
public async Task UpdateHassEntityStateAsync(string entityId, string payload)
|
|
{
|
|
Uri uri = new Uri(Hass_Base_Uri_Str + $"/states/{entityId}");
|
|
await _httpClient.PostAsync(uri, new StringContent(payload, Encoding.UTF8, "application/json"));
|
|
}
|
|
|
|
public async Task PublishEventAsync(OneDriveEvents eventType, string payload = "")
|
|
{
|
|
Uri uri = new Uri(Hass_Base_Uri_Str + $"/events/onedrive.{eventType}");
|
|
await _httpClient.PostAsync(uri, new StringContent(payload, Encoding.UTF8, "application/json"));
|
|
}
|
|
|
|
public async Task<string> DownloadBackupAsync(string backupSlug)
|
|
{
|
|
ConsoleLogger.LogInfo($"Fetching Local Backup (Slug:{backupSlug})");
|
|
Uri uri = new Uri(Supervisor_Base_Uri_Str + $"/backups/{backupSlug}/download");
|
|
var fileInfo = new FileInfo($"{LocalStorage.TempFolder}/{backupSlug}.tar");
|
|
await using var memStream = await _httpClient.GetStreamAsync(uri);
|
|
using var fileStream = System.IO.File.Create(fileInfo.FullName);
|
|
await memStream.CopyToAsync(fileStream);
|
|
ConsoleLogger.LogInfo($"Backup ({backupSlug}) fetched successfully");
|
|
return fileInfo.FullName;
|
|
}
|
|
|
|
public async Task<string> GetTimeZoneAsync()
|
|
{
|
|
Uri uri = new Uri(Supervisor_Base_Uri_Str + "/supervisor/info");
|
|
var response = await GetJsonResponseAsync<HassSupervisorInfoResponse>(uri);
|
|
var ret = response.DataProperty.Timezone;
|
|
return ret;
|
|
}
|
|
|
|
private async Task<T> GetJsonResponseAsync<T>(Uri uri)
|
|
{
|
|
string response = await _httpClient.GetStringAsync(uri);
|
|
T ret = JsonConvert.DeserializeObject<T>(response)!;
|
|
return ret;
|
|
}
|
|
|
|
public async Task<HassAddonInfoResponse> GetAddonInfo(string slug)
|
|
{
|
|
Uri uri = new Uri(Supervisor_Base_Uri_Str + $"/addons/{slug}/info");
|
|
var response = await GetJsonResponseAsync<HassAddonInfoResponse>(uri);
|
|
return response;
|
|
}
|
|
}
|
|
}
|