#Region " Option Statements "
Option Strict On
Option Explicit On
Option Infer Off
#End Region
#Region " Imports "
Imports Google.Apis.Auth.OAuth2
Imports Google.
Apis.
Drive.
v3 Imports Google.
Apis.
Drive.
v3.
Data Imports Google.Apis.Services
Imports Google.Apis.Upload
Imports Google.Apis.Util.Store
Imports Google.
Drive.
Enums
#End Region
#Region " Google Drive Client "
Namespace Google.
Drive.
Types
''' ----------------------------------------------------------------------------------------------------
''' <summary>
''' A client for Google Drive service.
''' </summary>
''' ----------------------------------------------------------------------------------------------------
Public NotInheritable Class DriveClient : Implements IDisposable
#Region " Private Fields "
Private client As DriveService
Private credential As UserCredential
Private ReadOnly authExceptionMessage As String =
"The user has not yet authorized the usage of this application.
Call 'DriveClient.Authorize()' or 'DriveClient.AuthorizeAsync()' methods."
Private scopeDict
As New Dictionary(Of DriveScopes,
String)(StringComparison.
Ordinal) From
{
{DriveScopes.
Full, DriveService.
Scope.
Drive},
{DriveScopes.ApplicationData, DriveService.Scope.DriveAppdata},
{DriveScopes.
Files, DriveService.
Scope.
DriveFile},
{DriveScopes.Metadata, DriveService.Scope.DriveMetadata},
{DriveScopes.MetadataReadonly, DriveService.Scope.DriveMetadataReadonly},
{DriveScopes.PhotosReadonly, DriveService.Scope.DrivePhotosReadonly},
{DriveScopes.ReadOnly, DriveService.Scope.DriveReadonly},
{DriveScopes.Scripts, DriveService.Scope.DriveScripts}
}
#End Region
#Region " Properties "
''' <summary>
''' Gets the client credentials.
''' </summary>
Public ReadOnly Property Secrets As ClientSecrets
''' <summary>
''' Gets the mail address to authorize Drive service. (e.g: "mail@gmail.com")
''' </summary>
Public ReadOnly Property MailAddress As String
''' <summary>
''' Gets the current Drive OAuthv2 scopes.
''' </summary>
Public ReadOnly Property Scopes As DriveScopes
''' <summary>
''' Gets a value that determines whether Google Drive API authorization was done.
''' </summary>
Public ReadOnly Property IsAuthorized As Boolean
Get
Return isAuthorizedB
End Get
End Property
Private isAuthorizedB As Boolean = False
#End Region
#Region " Constructors "
Private Sub New()
End Sub
''' <param name="apiFile">
''' The <c>client_secrets.json</c> file generated by Drive API console that contains the OAuthv2 login data
''' such as the client id, client secret, and redirection URI.
''' </param>
''' <param name="mailAddress">
''' The mail address to authorize Drive service. (e.g: "mail@gmail.com")
''' </param>
''' <param name="scopes">
''' The Drive OAuthv2 scope.
''' </param>
Public Sub New(apiFile As FileInfo, mailAddress As String, scopes As DriveScopes)
Me.MailAddress = mailAddress
Me.Scopes = scopes
Using sr As FileStream = apiFile.OpenRead()
Me.Secrets = GoogleClientSecrets.Load(sr).Secrets
End Using
End Sub
#End Region
#Region " Public Methods "
#Region " Authorization "
''' <summary>
''' Authorizes this instance to use Google Drive API services.
''' </summary>
''' <example>
''' <code>
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = client.Authorize()
''' </code>
''' </example>
Public Function Authorize() As UserCredential
Dim t As Task(Of UserCredential) = Task.Run(AddressOf Me.AuthorizeAsync)
t.Wait(Timeout.Infinite)
Return t.Result
End Function
''' <summary>
''' Authorizes this instance to use Google Drive API services.
''' </summary>
''' <example>
''' <code>
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = Await client.AuthorizeAsync()
''' </code>
''' </example>
Public Async Function AuthorizeAsync() As Task(Of UserCredential)
Dim scopeUrls As String() = GetScopeUrls(Scopes)
Me.credential =
Await GoogleWebAuthorizationBroker.AuthorizeAsync(Secrets,
scopeUrls.ToArray(),
MailAddress,
CancellationToken.None,
New FileDataStore("UNET", fullPath:=False))
Me.client = New DriveService(New BaseClientService.Initializer() With {
.HttpClientInitializer = Me.credential,
.ApplicationName = "UNET" ', .ApiKey = ""
})
isAuthorizedB = True
Return Me.credential
End Function
#End Region
#Region " Get Files "
''' <summary>
''' Gets all the files stored in the current user account.
''' </summary>
''' <example>
''' <code>
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = client.Authorize()
''' Dim files As List(Of File) = client.GetFiles()
'''
''' For Each file As File In files
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", file.Id))
''' .AppendLine(String.Format("Owned By Me?: {0}", file.OwnedByMe))
''' .AppendLine(String.Format("Name: {0}", file.Name))
''' End With
''' Console.WriteLine(sb.ToString)
''' Next file
''' </code>
''' </example>
Public Function GetFiles
() As List
(Of File) If Not (isAuthorizedB) Then
Throw New InvalidOperationException(authExceptionMessage)
Else
Dim t
As Task
(Of List
(Of File)) = Task.
Run(AddressOf GetFilesAsync
) t.Wait(Timeout.Infinite)
Return t.Result
End If
End Function
''' <summary>
''' Asynchronously gets all the files stored in the current user account.
''' </summary>
''' <example>
''' <code>
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = Await client.AuthorizeAsync()
''' Dim files As List(Of File) = Await client.GetFilesAsync()
'''
''' For Each file As File In files
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", file.Id))
''' .AppendLine(String.Format("Owned By Me?: {0}", file.OwnedByMe))
''' .AppendLine(String.Format("Name: {0}", file.Name))
''' End With
''' Console.WriteLine(sb.ToString)
''' Next file
''' </code>
''' </example>
Public Async
Function GetFilesAsync
() As Task
(Of List
(Of File))
If Not (isAuthorizedB) Then
Throw New InvalidOperationException(authExceptionMessage)
Else
Dim request
As FilesResource.
ListRequest = Me.
client.
Files.
List() With request
.PageSize = 100
.IncludeTeamDriveItems = False
.SupportsTeamDrives = False
.Fields = "nextPageToken, files"
.Q = "not mimeType contains 'folder'"
End With
Dim response As FileList = Await request.ExecuteAsync()
Do While True
Dim getRequest
As FilesResource.
GetRequest = Me.
client.
Files.
Get(file.
Id) With getRequest
.SupportsTeamDrives = False
.Fields = "*"
End With
Dim getResponse
As File = Await getRequest.
ExecuteAsync() getRequest.AcknowledgeAbuse = True
If Not String.IsNullOrEmpty(response.NextPageToken) Then
request.PageToken = response.NextPageToken
response = Await request.ExecuteAsync()
Else
Exit Do
End If
Loop
End If
End Function
''' <summary>
''' Asynchronously gets the files stored in the current user account that matches the specified search criteria.
''' </summary>
''' <example>
''' <code>
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = Await client.AuthorizeAsync()
''' Dim predicate As Func(Of File, Boolean) =
''' Function(f As File) f.Name.Equals("My Folder Name", StringComparison.OrdinalIgnoreCase)
''' Dim files As List(Of File) = Await client.GetFilesAsync(predicate)
'''
''' For Each file As File In files
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", file.Id))
''' .AppendLine(String.Format("Name: {0}", file.Name))
''' End With
''' Console.WriteLine(sb.ToString)
''' Next file
''' </code>
''' </example>
Public Async
Function GetFilesAsync
(predicate As Func(Of File,
Boolean)) As Task
(Of List
(Of File)) Return folders.
Where(predicate).
ToList() End Function
''' <summary>
''' Gets a file stored in the current user account that matches the specified file id.
''' </summary>
''' <example>
''' <code>
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = client.Authorize()
''' Dim file As File) = client.GetFileById(" File Id. ")
'''
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", file.Id))
''' .AppendLine(String.Format("Owned By Me?: {0}", file.OwnedByMe))
''' .AppendLine(String.Format("Name: {0}", file.Name))
''' End With
''' Console.WriteLine(sb.ToString)
''' </code>
''' </example>
Public Function GetFileById
(id
As String) As File If Not (isAuthorizedB) Then
Throw New InvalidOperationException(authExceptionMessage)
Else
Dim t
As Task
(Of File) = Task.
Run(Function() GetFileByIdAsync
(id
)) t.Wait(Timeout.Infinite)
Return t.Result
End If
End Function
''' <summary>
''' Asynchronously gets a file stored in the current user account that matches the specified file id.
''' </summary>
''' <example>
''' <code>
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = Await client.AuthorizeAsync()
''' Dim file As File) = Await client.GetFileByIdAsync(" File Id. ")
'''
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", file.Id))
''' .AppendLine(String.Format("Owned By Me?: {0}", file.OwnedByMe))
''' .AppendLine(String.Format("Name: {0}", file.Name))
''' End With
''' Console.WriteLine(sb.ToString)
''' </code>
''' </example>
Public Async
Function GetFileByIdAsync
(id
As String) As Task
(Of File) If Not (isAuthorizedB) Then
Throw New InvalidOperationException(authExceptionMessage)
Else
Dim predicate As Func(Of File,
Boolean) = Function(f
As File) f.
Id.
Equals(id, StringComparison.
OrdinalIgnoreCase)
Dim result
As List
(Of File) = Await Task.
Run(Function() GetFilesAsync
(predicate)) Return result.DefaultIfEmpty(Nothing).SingleOrDefault()
End If
End Function
#End Region
#Region " Update (replace) File "
''' <summary>
''' Updates (replaces) a existing file in the specified folder.
''' </summary>
''' <example>
''' <code>
''' Private Sub UpdateFile()
'''
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = client.Authorize()
'''
''' Dim srcFile As New FileInfo("C:\File.ext")
''' Dim dstFile As File = client.GetFilesByName("File to update.ext").Single()
'''
''' Dim result As KeyValuePair(Of Upload.ResumableUpload, File) =
''' client.UpdateFile(srcFile, dstFile)
'''
''' Dim upload As ResumableUpload = result.Key
'''
''' Select Case upload.GetProgress().Status
'''
''' Case Upload.UploadStatus.Failed
''' Console.WriteLine("Upload Failed.")
''' ' ToDo: Retry/Resume Upload?:
''' ' upload.Upload()
''' ' upload.Resume()
'''
''' Case Upload.UploadStatus.Completed
''' Dim dstFile As ResumableUpload = result.Value
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", dstFile.Id))
''' .AppendLine(String.Format("Name: {0}", dstFile.Name))
''' End With
''' Console.WriteLine(sb.ToString)
'''
''' End Select
'''
''' End Sub
''' </code>
''' </example>
''' <param name="srcFile">
''' The source file to upload.
''' </param>
''' <param name="dstFile">
''' The metadata of the existing file being updated.
''' </param>
Public Function UpdateFile
(srcFile
As FileInfo, dstFile
As File) As KeyValuePair
(Of ResumableUpload,
File) If Not (isAuthorizedB) Then
Throw New InvalidOperationException(authExceptionMessage)
Else
Dim t
As Task
(Of KeyValuePair
(Of ResumableUpload,
File)) = Task.Run(Function() Me.UpdateFileAsync(srcFile, dstFile, Nothing, Nothing))
t.Wait(Timeout.Infinite)
Return t.Result
End If
End Function
''' <summary>
''' Updates (replaces) a existing file in the specified folder.
''' </summary>
''' <example>
''' <code>
''' Private Sub UpdateFile()
'''
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = client.Authorize()
'''
''' Dim srcFile As New FileInfo("C:\File.ext")
'''
''' Dim result As KeyValuePair(Of Upload.ResumableUpload, File) =
''' client.UpdateFile(srcFile, "File Id")
'''
''' Dim upload As ResumableUpload = result.Key
'''
''' Select Case upload.GetProgress().Status
'''
''' Case Upload.UploadStatus.Failed
''' Console.WriteLine("Upload Failed.")
''' ' ToDo: Retry/Resume Upload?:
''' ' upload.Upload()
''' ' upload.Resume()
'''
''' Case Upload.UploadStatus.Completed
''' Dim dstFile As ResumableUpload = result.Value
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", dstFile.Id))
''' .AppendLine(String.Format("Name: {0}", dstFile.Name))
''' End With
''' Console.WriteLine(sb.ToString)
'''
''' End Select
'''
''' End Sub
''' </code>
''' </example>
''' <param name="srcFile">
''' The source file to upload.
''' </param>
''' <param name="dstFileId">
''' The identifier of the existing file being updated.
''' </param>
Public Function UpdateFile
(srcFile
As FileInfo, dstFileId
As String) As KeyValuePair
(Of ResumableUpload,
File) If Not (isAuthorizedB) Then
Throw New InvalidOperationException(authExceptionMessage)
Else
Dim dstFile
As File = GetFileById
(dstFileId
) If (dstFile Is Nothing) Then
Throw New Exception(String.Format("File not found with the specified Id: {0}", dstFileId))
End If
Dim t
As Task
(Of KeyValuePair
(Of ResumableUpload,
File)) = Task.Run(Function() Me.UpdateFileAsync(srcFile, dstFile, Nothing, Nothing))
t.Wait(Timeout.Infinite)
Return t.Result
End If
End Function
''' <summary>
''' Asynchronously updates (replaces) a existing file in the specified folder.
''' </summary>
''' <example>
''' <code>
''' Private Async Sub UpdateFile()
'''
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = Await client.AuthorizeAsync()
'''
''' Dim srcFile As New FileInfo("C:\File.ext")
''' Dim dstFile As File = client.GetFilesByName("File to update.ext").Single()
'''
''' Dim result As KeyValuePair(Of Upload.ResumableUpload, File) =
''' Await client.UpdateFileAsync(srcFile, dstFile, AddressOf Me.Upload_ProgressChanged, Nothing)
'''
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", result.Value.Id))
''' .AppendLine(String.Format("Name: {0}", result.Value.Name))
''' End With
''' Console.WriteLine(sb.ToString)
'''
''' End Sub
'''
''' Public Sub Upload_ProgressChanged(e As Upload.IUploadProgress)
'''
''' Select Case e.Status
'''
''' Case Upload.UploadStatus.Uploading
''' Console.WriteLine("Bytes sent: {0}", e.BytesSent)
'''
''' Case Upload.UploadStatus.Completed
''' Console.WriteLine("Upload completed.")
'''
''' Case Upload.UploadStatus.Failed
''' Console.WriteLine("Upload failed. Reason: {0}", e.Exception.Message)
'''
''' Case Else
''' ' Do Nothing.
'''
''' End Select
'''
''' End Sub
''' </code>
''' </example>
''' <param name="srcFile">
''' The source file to upload.
''' </param>
''' <param name="dstFile">
''' The metadata of the existing file being updated.
''' </param>
''' <param name="progressHandler">
''' A event handler that will receive progress changes of the upload operation.
''' </param>
''' <param name="cancellationToken">
''' A cancellation token to cancel the upload operation.
''' </param>
Public Async Function UpdateFileAsync(srcFile As FileInfo,
progressHandler As Action(Of IUploadProgress),
cancellationToken
As CancellationToken
) As Task
(Of KeyValuePair
(Of ResumableUpload,
File))
If Not (isAuthorizedB) Then
Throw New InvalidOperationException(authExceptionMessage)
Else
Dim request As FilesResource.UpdateMediaUpload
Dim progress As IUploadProgress
Using stream As New FileStream(srcFile.FullName, FileMode.Open, FileAccess.Read, FileShare.Read)
Dim dstFileTemp
As New File() With { .AppProperties = dstFile.AppProperties,
.Name = srcFile.Name,
.Description = dstFile.Description,
.Kind = dstFile.Kind,
.Properties = dstFile.Properties,
.OriginalFilename = dstFile.OriginalFilename,
.Trashed = dstFile.Trashed,
.WritersCanShare = dstFile.WritersCanShare
}
request
= Me.
client.
Files.
Update(dstFileTemp, dstFile.
Id, stream, dstFile.
MimeType) With request
.AddParents = String.Join(",", dstFile.Parents)
.ChunkSize = 262144
.SupportsTeamDrives = False
.Fields = "*"
End With
AddHandler request.ProgressChanged, progressHandler
progress = Await request.UploadAsync(cancellationToken)
RemoveHandler request.ProgressChanged, progressHandler
End Using
Dim response
As File = request.
ResponseBody Return New KeyValuePair
(Of ResumableUpload,
File)(request, response
)
End If
End Function
''' <summary>
''' Asynchronously updates (replaces) a existing file in the specified folder.
''' </summary>
''' <example>
''' <code>
''' Private Async Sub UpdateFile()
'''
''' Dim client As New DriveClient("C:\secrets.json", "mail@gmail.com", DriveScopes.Full)
''' Dim credential As UserCredential = Await client.AuthorizeAsync()
'''
''' Dim srcFile As New FileInfo("C:\File.ext")
'''
''' Dim result As KeyValuePair(Of Upload.ResumableUpload, File) =
''' Await client.UpdateFileAsync(srcFile, "File Id", AddressOf Me.Upload_ProgressChanged, Nothing)
'''
''' Dim sb As New StringBuilder
''' With sb
''' .AppendLine(String.Format("Id: {0}", result.Value.Id))
''' .AppendLine(String.Format("Name: {0}", result.Value.Name))
''' End With
''' Console.WriteLine(sb.ToString)
'''
''' End Sub
'''
''' Public Sub Upload_ProgressChanged(e As Upload.IUploadProgress)
'''
''' Select Case e.Status
'''
'''
''' Case Upload.UploadStatus.Uploading
''' Console.WriteLine("Bytes sent: {0}", e.BytesSent)
'''
''' Case Upload.UploadStatus.Completed
''' Console.WriteLine("Upload completed.")
'''
''' Case Upload.UploadStatus.Failed
''' Console.WriteLine("Upload failed. Reason: {0}", e.Exception.Message)
'''
''' Case Else
''' ' Do Nothing.
'''
''' End Select
'''
''' End Sub
''' </code>
''' </example>
''' <param name="srcFile">
''' The source file to upload.
''' </param>
''' <param name="dstFileId">
''' The identifier of the existing file being updated.
''' </param>
''' <param name="progressHandler">
''' A event handler that will receive progress changes of the upload operation.
''' </param>
''' <param name="cancellationToken">
''' A cancellation token to cancel the upload operation.
''' </param>
Public Async Function UpdateFileAsync(srcFile As FileInfo,
dstFileId As String,
progressHandler As Action(Of IUploadProgress),
cancellationToken
As CancellationToken
) As Task
(Of KeyValuePair
(Of ResumableUpload,
File))
If Not (isAuthorizedB) Then
Throw New InvalidOperationException(authExceptionMessage)
Else
Dim dstFile
As File = Await GetFileByIdAsync
(dstFileId
) If (dstFile Is Nothing) Then
Throw New Exception(String.Format("File not found with the specified Id: {0}", dstFileId))
End If
Return Await Me.UpdateFileAsync(srcFile, dstFile, progressHandler, cancellationToken)
End If
End Function
#End Region
#End Region
#Region " Private Methods "
Private Function GetScopeUrls(scopes As DriveScopes) As String()
Return (From scope As KeyValuePair(Of DriveScopes, String) In Me.scopeDict
Where Scopes.HasFlag(scope.Key)
Select scope.Value).ToArray()
End Function
#End Region
#Region " IDisposable Implementation "
Private isDisposed As Boolean = False
Public Sub Dispose() Implements IDisposable.Dispose
Me.Dispose(isDisposing:=True)
GC.SuppressFinalize(obj:=Me)
End Sub
Private Sub Dispose(isDisposing As Boolean)
If (Not Me.isDisposed) AndAlso (isDisposing) Then
If (Me.client IsNot Nothing) Then
Me.client.Dispose()
Me.client = Nothing
End If
End If
Me.isDisposed = True
End Sub
#End Region
End Class
End Namespace
#End Region