Skip to content

Commit

Permalink
Merge branch 'master' into feature/new-adapter-google-cloud-storage
Browse files Browse the repository at this point in the history
  • Loading branch information
mvdgun committed Jan 10, 2024
2 parents 8c73c61 + b71260a commit 22ec1b5
Show file tree
Hide file tree
Showing 8 changed files with 320 additions and 14 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<RootNamespace>SharpGrip.FileSystem.Adapters.GoogleCloudStorage</RootNamespace>
</PropertyGroup>

<PropertyGroup>
<AssemblyName>SharpGrip.FileSystem.Adapters.GoogleCloudStorage</AssemblyName>
<PackageId>SharpGrip.FileSystem.Adapters.GoogleCloudStorage</PackageId>
<Title>SharpGrip FileSystem Google Cloud Storage adapter</Title>
<Description>The SharpGrip FileSystem Google Cloud Storage adapter.</Description>
<PackageTags>sharpgrip;file-system;google-cloud-storage</PackageTags>
</PropertyGroup>

<ItemGroup>
<None Include="..\README.md" Pack="true" PackagePath="\" />
</ItemGroup>

<ItemGroup>
<PackageReference Include="Google.Cloud.Storage.V1" Version="4.7.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\FileSystem\FileSystem.csproj"/>
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Google.Cloud.Storage.V1;
using SharpGrip.FileSystem.Exceptions;
using SharpGrip.FileSystem.Extensions;
using SharpGrip.FileSystem.Models;
using DirectoryNotFoundException = SharpGrip.FileSystem.Exceptions.DirectoryNotFoundException;
using FileNotFoundException = SharpGrip.FileSystem.Exceptions.FileNotFoundException;

namespace SharpGrip.FileSystem.Adapters.GoogleCloudStorage
{
public class GoogleCloudStorageAdapter : Adapter<GoogleCloudStorageAdapterConfiguration, string, string>
{
private readonly StorageClient client;
private readonly string bucketName;

public GoogleCloudStorageAdapter(string prefix, string rootPath, StorageClient client, string bucketName, Action<GoogleCloudStorageAdapterConfiguration>? configuration = null)
: base(prefix, rootPath, configuration)
{
this.client = client;
this.bucketName = bucketName;
}

public override void Dispose()
{
client.Dispose();
}

public override async Task ConnectAsync(CancellationToken cancellationToken = default)
{
Logger.LogStartConnectingAdapter(this);
await Task.CompletedTask;
Logger.LogFinishedConnectingAdapter(this);
}

public override async Task<IFile> GetFileAsync(string virtualPath, CancellationToken cancellationToken = default)
{
var path = GetPath(virtualPath).RemoveLeadingForwardSlash().RemoveTrailingForwardSlash();

try
{
var file = await client.GetObjectAsync(bucketName, path, new GetObjectOptions(), cancellationToken);

if (file == null)
{
throw new FileNotFoundException(path, Prefix);
}

return ModelFactory.CreateFile(file, path, virtualPath);
}
catch (Exception exception)
{
throw Exception(exception);
}
}

public override async Task<IDirectory> GetDirectoryAsync(string virtualPath, CancellationToken cancellationToken = default)
{
var path = GetPath(virtualPath).EnsureLeadingForwardSlash().EnsureTrailingForwardSlash();
var parentPath = GetParentPathPart(path).EnsureTrailingForwardSlash();

try
{
var request = client.Service.Objects.List(bucketName);

request.Prefix = parentPath == "/" ? null : parentPath;
request.Delimiter = "/";

do
{
var objects = await request.ExecuteAsync(cancellationToken: cancellationToken);

foreach (var directoryName in objects.Prefixes)
{
var directoryPath = parentPath + directoryName;

if (directoryPath == path)
{
return ModelFactory.CreateDirectory(directoryName.RemoveTrailingForwardSlash(), directoryPath, GetVirtualPath(directoryPath));
}
}

request.PageToken = objects.NextPageToken;
} while (request.PageToken != null);

throw new DirectoryNotFoundException(path, Prefix);
}
catch (Exception exception)
{
throw Exception(exception);
}
}

public override async Task<IEnumerable<IFile>> GetFilesAsync(string virtualPath = "", CancellationToken cancellationToken = default)
{
await GetDirectoryAsync(virtualPath, cancellationToken);

var path = GetPath(virtualPath).RemoveLeadingForwardSlash().EnsureTrailingForwardSlash();

try
{
var files = new List<IFile>();

var request = client.Service.Objects.List(bucketName);

request.Prefix = path == "/" ? null : path;
request.Delimiter = "/";

do
{
var objects = await request.ExecuteAsync(cancellationToken: cancellationToken);

foreach (var file in objects.Items)
{
var filePath = path + file.Name;

files.Add(ModelFactory.CreateFile(file, filePath.RemoveTrailingForwardSlash(), GetVirtualPath(filePath)));
}

request.PageToken = objects.NextPageToken;
} while (request.PageToken != null);

return files;
}
catch (Exception exception)
{
throw Exception(exception);
}
}

public override async Task<IEnumerable<IDirectory>> GetDirectoriesAsync(string virtualPath = "", CancellationToken cancellationToken = default)
{
await GetDirectoryAsync(virtualPath, cancellationToken);

var path = GetPath(virtualPath).RemoveLeadingForwardSlash().EnsureTrailingForwardSlash();

try
{
var directories = new List<IDirectory>();

var request = client.Service.Objects.List(bucketName);

request.Prefix = path == "/" ? null : path;
request.Delimiter = "/";

do
{
var objects = await request.ExecuteAsync(cancellationToken: cancellationToken);

foreach (var directoryName in objects.Prefixes)
{
var directoryPath = path + directoryName;

directories.Add(ModelFactory.CreateDirectory(directoryName.RemoveTrailingForwardSlash(), directoryPath.EnsureTrailingForwardSlash(), GetVirtualPath(directoryPath)));
}

request.PageToken = objects.NextPageToken;
} while (request.PageToken != null);

return directories;
}
catch (Exception exception)
{
throw Exception(exception);
}
}

public override async Task CreateDirectoryAsync(string virtualPath, CancellationToken cancellationToken = default)
{
if (await DirectoryExistsAsync(virtualPath, cancellationToken))
{
throw new DirectoryExistsException(GetPath(virtualPath), Prefix);
}

var path = GetPath(virtualPath).RemoveLeadingForwardSlash().EnsureTrailingForwardSlash();

try
{
// client.Service.

await client.UploadObjectAsync(bucketName, GetLastPathPart(path).EnsureTrailingForwardSlash(), null, Stream.Null, cancellationToken: cancellationToken);
}
catch (Exception exception)
{
throw Exception(exception);
}
}

public override async Task DeleteDirectoryAsync(string virtualPath, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public override async Task DeleteFileAsync(string virtualPath, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public override async Task<Stream> ReadFileStreamAsync(string virtualPath, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

public override async Task WriteFileAsync(string virtualPath, Stream contents, bool overwrite = false, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}

protected override Exception Exception(Exception exception)
{
if (exception is FileSystemException)
{
return exception;
}

return new AdapterRuntimeException(exception);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
using SharpGrip.FileSystem.Configuration;

namespace SharpGrip.FileSystem.Adapters.GoogleCloudStorage
{
public class GoogleCloudStorageAdapterConfiguration : AdapterConfiguration
{
}
}
43 changes: 43 additions & 0 deletions FileSystem.Adapters.GoogleCloudStorage/src/ModelFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
using Google.Apis.Storage.v1.Data;
using SharpGrip.FileSystem.Models;

namespace SharpGrip.FileSystem.Adapters.GoogleCloudStorage
{
public static class ModelFactory
{
public static FileModel CreateFile(Object file, string path, string virtualPath)
{
return new FileModel
{
Name = file.Name,
Path = path,
VirtualPath = virtualPath,
Length = (long?) file.Size,
LastModifiedDateTime = file.UpdatedDateTimeOffset?.DateTime,
CreatedDateTime = file.TimeCreatedDateTimeOffset?.DateTime
};
}

public static DirectoryModel CreateDirectory(string name, string path, string virtualPath)
{
return new DirectoryModel
{
Name = name,
Path = path,
VirtualPath = virtualPath
};
}

public static DirectoryModel CreateDirectory(Object directory, string path, string virtualPath)
{
return new DirectoryModel
{
Name = directory.Name,
Path = path,
VirtualPath = virtualPath,
LastModifiedDateTime = directory.UpdatedDateTimeOffset?.DateTime,
CreatedDateTime = directory.TimeCreatedDateTimeOffset?.DateTime
};
}
}
}
6 changes: 6 additions & 0 deletions FileSystem.sln
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.Dropbox
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.Ftp", "FileSystem.Adapters.Ftp\FileSystem.Adapters.Ftp.csproj", "{ED38402A-3667-4701-A974-4D7710E1544A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.GoogleCloudStorage", "FileSystem.Adapters.GoogleCloudStorage\FileSystem.Adapters.GoogleCloudStorage.csproj", "{0E6E0F36-55C4-49FF-9298-99D5B3309381}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.GoogleDrive", "FileSystem.Adapters.GoogleDrive\FileSystem.Adapters.GoogleDrive.csproj", "{CB1F411C-3FB5-4441-9541-423951C17BAF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.MicrosoftOneDrive", "FileSystem.Adapters.MicrosoftOneDrive\FileSystem.Adapters.MicrosoftOneDrive.csproj", "{9955422E-4A50-43CD-BC2B-91E6820F206C}"
Expand Down Expand Up @@ -50,6 +52,10 @@ Global
{ED38402A-3667-4701-A974-4D7710E1544A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{ED38402A-3667-4701-A974-4D7710E1544A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{ED38402A-3667-4701-A974-4D7710E1544A}.Release|Any CPU.Build.0 = Release|Any CPU
{0E6E0F36-55C4-49FF-9298-99D5B3309381}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0E6E0F36-55C4-49FF-9298-99D5B3309381}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0E6E0F36-55C4-49FF-9298-99D5B3309381}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0E6E0F36-55C4-49FF-9298-99D5B3309381}.Release|Any CPU.Build.0 = Release|Any CPU
{CB1F411C-3FB5-4441-9541-423951C17BAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CB1F411C-3FB5-4441-9541-423951C17BAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CB1F411C-3FB5-4441-9541-423951C17BAF}.Release|Any CPU.ActiveCfg = Release|Any CPU
Expand Down
2 changes: 1 addition & 1 deletion FileSystem/FileSystem.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<PackageId>SharpGrip.FileSystem</PackageId>
<Title>SharpGrip FileSystem</Title>
<Description>SharpGrip FileSystem is a file system abstraction supporting multiple adapters.</Description>
<PackageTags>sharpgrip;file-system;amazon-s3;azure-blob-storage;azure-file-storage;dropbox;ftp;google-drive;microsoft-onedrive;sftp</PackageTags>
<PackageTags>sharpgrip;file-system;amazon-s3;azure-blob-storage;azure-file-storage;dropbox;ftp;google-cloud-storage;google-drive;microsoft-onedrive;sftp</PackageTags>
</PropertyGroup>

<ItemGroup>
Expand Down
4 changes: 2 additions & 2 deletions FileSystem/src/Adapters/Adapter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -129,9 +129,9 @@ public virtual async Task AppendFileAsync(string virtualPath, Stream contents, C
public abstract Task WriteFileAsync(string virtualPath, Stream contents, bool overwrite = false, CancellationToken cancellationToken = default);
protected abstract Exception Exception(Exception exception);

protected string GetPath(string path)
protected string GetPath(string virtualPath)
{
return PathUtilities.GetPath(path, RootPath);
return PathUtilities.GetPath(virtualPath, RootPath);
}

protected string GetVirtualPath(string path)
Expand Down
Loading

0 comments on commit 22ec1b5

Please sign in to comment.