Mesen-X/GUI.NET/GoogleDriveIntegration/GoogleDriveAccessor.cs

212 lines
5.7 KiB
C#

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Auth.OAuth2.Responses;
using Google.Apis.Download;
using Google.Apis.Drive.v3;
using Google.Apis.Drive.v3.Data;
using Google.Apis.Services;
using Google.Apis.Upload;
namespace Mesen.GUI.GoogleDriveIntegration
{
public enum FileDownloadResult
{
OK = 0,
FileNotFound = 1,
Error = 2,
FileCorrupted = 3,
};
public class GoogleDriveAccessor : IDisposable
{
private const string _contentType = @"application/zip";
private readonly string[] _scopes = new[] { DriveService.Scope.DriveAppdata };
private UserCredential _credentials = null;
private DriveService _service = null;
private bool _connected = false;
private bool _revoked = false;
public bool Revoked { get { return _revoked; } }
public bool UploadFile(System.IO.MemoryStream fileStream, string filename)
{
fileStream.Position = 0;
try {
this.Connect().GetAwaiter().GetResult();
if(_connected) {
this.UploadFileAsync(fileStream, filename).GetAwaiter().GetResult();
}
} catch(TokenResponseException) {
_revoked = true;
_connected = false;
_credentials = null;
_service = null;
} catch {
_connected = false;
_credentials = null;
_service = null;
}
return _connected;
}
public FileDownloadResult DownloadFile(System.IO.MemoryStream fileStream, string filename)
{
try {
this.Connect().GetAwaiter().GetResult();
if(_connected) {
return this.DownloadFileAsync(fileStream, filename).GetAwaiter().GetResult();
}
} catch(TokenResponseException) {
_revoked = true;
_connected = false;
_credentials = null;
_service = null;
} catch {
_connected = false;
_credentials = null;
_service = null;
}
return FileDownloadResult.Error;
}
public bool AcquireToken()
{
this.Connect().GetAwaiter().GetResult();
return _connected;
}
public void RevokeToken()
{
Task.Run(async () => {
try {
_credentials = await this.GetCredentials().ConfigureAwait(false);
await _credentials.RevokeTokenAsync(CancellationToken.None).ConfigureAwait(false);
} catch {
}
_service = null;
_credentials = null;
}).Wait();
}
private async Task Connect()
{
if(_service == null) {
try {
_credentials = await this.GetCredentials().ConfigureAwait(false);
_service = new DriveService(new BaseClientService.Initializer() {
HttpClientInitializer = _credentials,
ApplicationName = "Mesen",
});
_connected = true;
} catch(AggregateException ex) {
foreach(Exception innerException in ex.InnerExceptions) {
if(innerException is TokenResponseException) {
_connected = false;
_revoked = true;
}
}
_connected = false;
_credentials = null;
_service = null;
} catch {
_connected = false;
_credentials = null;
_service = null;
}
}
}
private async Task<UserCredential> GetCredentials()
{
var clientSecrets = new ClientSecrets { ClientId = "478233037635-nf90q052c32suhm0l8r9fkkk34k7hkl5.apps.googleusercontent.com", ClientSecret = "zGatV81vs5kKuhHq3fZuw4lc" };
GoogleWebAuthorizationBroker.Folder = System.IO.Path.Combine(Config.ConfigManager.HomeFolder, "GoogleDrive");
return await GoogleWebAuthorizationBroker.AuthorizeAsync(clientSecrets, _scopes, Environment.UserName, CancellationToken.None, codeReceiver: new MesenCodeReceiver()).ConfigureAwait(false);
}
private File GetFileMatchingName(string filename)
{
var listService = _service.Files.List();
listService.Spaces = "appDataFolder";
foreach(File file in listService.Execute().Files) {
if(file.Name == filename) {
return file;
}
}
return null;
}
private Task<IUploadProgress> UploadFileAsync(System.IO.MemoryStream fileStream, string filename)
{
File driveFile = this.GetFileMatchingName(filename);
Task<IUploadProgress> task;
if(driveFile == null) {
//File does not exist, create it
var insert = _service.Files.Create(new File { Name = "MesenData.zip", Parents = new List<string>() { "appDataFolder" } }, fileStream, _contentType);
insert.ChunkSize = FilesResource.CreateMediaUpload.MinimumChunkSize * 2;
insert.ResponseReceived += Upload_ResponseReceived;
task = insert.UploadAsync();
} else {
//File exists, update it
var update = _service.Files.Update(null, driveFile.Id, fileStream, _contentType);
update.ResponseReceived += Upload_ResponseReceived;
task = update.UploadAsync();
}
task.ContinueWith(t => {
// NotOnRanToCompletion - this code will be called if the upload fails
Console.WriteLine("Upload Failed. " + t.Exception);
}, TaskContinuationOptions.NotOnRanToCompletion);
task.ContinueWith(t => {
fileStream.Dispose();
});
return task;
}
private async Task<FileDownloadResult> DownloadFileAsync(System.IO.MemoryStream outStream, string filename)
{
File driveFile = this.GetFileMatchingName(filename);
if(driveFile != null) {
var request = _service.Files.Get(driveFile.Id);
var progress = await request.DownloadAsync(outStream).ConfigureAwait(false);
if(progress.Status == DownloadStatus.Completed) {
return FileDownloadResult.OK;
} else {
return FileDownloadResult.Error;
}
}
return FileDownloadResult.FileNotFound;
}
public async Task DeleteFile(string filename)
{
this.Connect().GetAwaiter().GetResult();
File driveFile = this.GetFileMatchingName(filename);
await _service.Files.Delete(driveFile.Id).ExecuteAsync().ConfigureAwait(false);
}
void Upload_ResponseReceived(File file)
{
}
void IDisposable.Dispose()
{
if(_service != null) {
_service.Dispose();
}
}
}
}