Skip to content

Commit 22ec1b5

Browse files
committed
Merge branch 'master' into feature/new-adapter-google-cloud-storage
2 parents 8c73c61 + b71260a commit 22ec1b5

8 files changed

Lines changed: 320 additions & 14 deletions

File tree

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<RootNamespace>SharpGrip.FileSystem.Adapters.GoogleCloudStorage</RootNamespace>
5+
</PropertyGroup>
6+
7+
<PropertyGroup>
8+
<AssemblyName>SharpGrip.FileSystem.Adapters.GoogleCloudStorage</AssemblyName>
9+
<PackageId>SharpGrip.FileSystem.Adapters.GoogleCloudStorage</PackageId>
10+
<Title>SharpGrip FileSystem Google Cloud Storage adapter</Title>
11+
<Description>The SharpGrip FileSystem Google Cloud Storage adapter.</Description>
12+
<PackageTags>sharpgrip;file-system;google-cloud-storage</PackageTags>
13+
</PropertyGroup>
14+
15+
<ItemGroup>
16+
<None Include="..\README.md" Pack="true" PackagePath="\" />
17+
</ItemGroup>
18+
19+
<ItemGroup>
20+
<PackageReference Include="Google.Cloud.Storage.V1" Version="4.7.0" />
21+
</ItemGroup>
22+
23+
<ItemGroup>
24+
<ProjectReference Include="..\FileSystem\FileSystem.csproj"/>
25+
</ItemGroup>
26+
27+
</Project>
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.IO;
4+
using System.Threading;
5+
using System.Threading.Tasks;
6+
using Google.Cloud.Storage.V1;
7+
using SharpGrip.FileSystem.Exceptions;
8+
using SharpGrip.FileSystem.Extensions;
9+
using SharpGrip.FileSystem.Models;
10+
using DirectoryNotFoundException = SharpGrip.FileSystem.Exceptions.DirectoryNotFoundException;
11+
using FileNotFoundException = SharpGrip.FileSystem.Exceptions.FileNotFoundException;
12+
13+
namespace SharpGrip.FileSystem.Adapters.GoogleCloudStorage
14+
{
15+
public class GoogleCloudStorageAdapter : Adapter<GoogleCloudStorageAdapterConfiguration, string, string>
16+
{
17+
private readonly StorageClient client;
18+
private readonly string bucketName;
19+
20+
public GoogleCloudStorageAdapter(string prefix, string rootPath, StorageClient client, string bucketName, Action<GoogleCloudStorageAdapterConfiguration>? configuration = null)
21+
: base(prefix, rootPath, configuration)
22+
{
23+
this.client = client;
24+
this.bucketName = bucketName;
25+
}
26+
27+
public override void Dispose()
28+
{
29+
client.Dispose();
30+
}
31+
32+
public override async Task ConnectAsync(CancellationToken cancellationToken = default)
33+
{
34+
Logger.LogStartConnectingAdapter(this);
35+
await Task.CompletedTask;
36+
Logger.LogFinishedConnectingAdapter(this);
37+
}
38+
39+
public override async Task<IFile> GetFileAsync(string virtualPath, CancellationToken cancellationToken = default)
40+
{
41+
var path = GetPath(virtualPath).RemoveLeadingForwardSlash().RemoveTrailingForwardSlash();
42+
43+
try
44+
{
45+
var file = await client.GetObjectAsync(bucketName, path, new GetObjectOptions(), cancellationToken);
46+
47+
if (file == null)
48+
{
49+
throw new FileNotFoundException(path, Prefix);
50+
}
51+
52+
return ModelFactory.CreateFile(file, path, virtualPath);
53+
}
54+
catch (Exception exception)
55+
{
56+
throw Exception(exception);
57+
}
58+
}
59+
60+
public override async Task<IDirectory> GetDirectoryAsync(string virtualPath, CancellationToken cancellationToken = default)
61+
{
62+
var path = GetPath(virtualPath).EnsureLeadingForwardSlash().EnsureTrailingForwardSlash();
63+
var parentPath = GetParentPathPart(path).EnsureTrailingForwardSlash();
64+
65+
try
66+
{
67+
var request = client.Service.Objects.List(bucketName);
68+
69+
request.Prefix = parentPath == "/" ? null : parentPath;
70+
request.Delimiter = "/";
71+
72+
do
73+
{
74+
var objects = await request.ExecuteAsync(cancellationToken: cancellationToken);
75+
76+
foreach (var directoryName in objects.Prefixes)
77+
{
78+
var directoryPath = parentPath + directoryName;
79+
80+
if (directoryPath == path)
81+
{
82+
return ModelFactory.CreateDirectory(directoryName.RemoveTrailingForwardSlash(), directoryPath, GetVirtualPath(directoryPath));
83+
}
84+
}
85+
86+
request.PageToken = objects.NextPageToken;
87+
} while (request.PageToken != null);
88+
89+
throw new DirectoryNotFoundException(path, Prefix);
90+
}
91+
catch (Exception exception)
92+
{
93+
throw Exception(exception);
94+
}
95+
}
96+
97+
public override async Task<IEnumerable<IFile>> GetFilesAsync(string virtualPath = "", CancellationToken cancellationToken = default)
98+
{
99+
await GetDirectoryAsync(virtualPath, cancellationToken);
100+
101+
var path = GetPath(virtualPath).RemoveLeadingForwardSlash().EnsureTrailingForwardSlash();
102+
103+
try
104+
{
105+
var files = new List<IFile>();
106+
107+
var request = client.Service.Objects.List(bucketName);
108+
109+
request.Prefix = path == "/" ? null : path;
110+
request.Delimiter = "/";
111+
112+
do
113+
{
114+
var objects = await request.ExecuteAsync(cancellationToken: cancellationToken);
115+
116+
foreach (var file in objects.Items)
117+
{
118+
var filePath = path + file.Name;
119+
120+
files.Add(ModelFactory.CreateFile(file, filePath.RemoveTrailingForwardSlash(), GetVirtualPath(filePath)));
121+
}
122+
123+
request.PageToken = objects.NextPageToken;
124+
} while (request.PageToken != null);
125+
126+
return files;
127+
}
128+
catch (Exception exception)
129+
{
130+
throw Exception(exception);
131+
}
132+
}
133+
134+
public override async Task<IEnumerable<IDirectory>> GetDirectoriesAsync(string virtualPath = "", CancellationToken cancellationToken = default)
135+
{
136+
await GetDirectoryAsync(virtualPath, cancellationToken);
137+
138+
var path = GetPath(virtualPath).RemoveLeadingForwardSlash().EnsureTrailingForwardSlash();
139+
140+
try
141+
{
142+
var directories = new List<IDirectory>();
143+
144+
var request = client.Service.Objects.List(bucketName);
145+
146+
request.Prefix = path == "/" ? null : path;
147+
request.Delimiter = "/";
148+
149+
do
150+
{
151+
var objects = await request.ExecuteAsync(cancellationToken: cancellationToken);
152+
153+
foreach (var directoryName in objects.Prefixes)
154+
{
155+
var directoryPath = path + directoryName;
156+
157+
directories.Add(ModelFactory.CreateDirectory(directoryName.RemoveTrailingForwardSlash(), directoryPath.EnsureTrailingForwardSlash(), GetVirtualPath(directoryPath)));
158+
}
159+
160+
request.PageToken = objects.NextPageToken;
161+
} while (request.PageToken != null);
162+
163+
return directories;
164+
}
165+
catch (Exception exception)
166+
{
167+
throw Exception(exception);
168+
}
169+
}
170+
171+
public override async Task CreateDirectoryAsync(string virtualPath, CancellationToken cancellationToken = default)
172+
{
173+
if (await DirectoryExistsAsync(virtualPath, cancellationToken))
174+
{
175+
throw new DirectoryExistsException(GetPath(virtualPath), Prefix);
176+
}
177+
178+
var path = GetPath(virtualPath).RemoveLeadingForwardSlash().EnsureTrailingForwardSlash();
179+
180+
try
181+
{
182+
// client.Service.
183+
184+
await client.UploadObjectAsync(bucketName, GetLastPathPart(path).EnsureTrailingForwardSlash(), null, Stream.Null, cancellationToken: cancellationToken);
185+
}
186+
catch (Exception exception)
187+
{
188+
throw Exception(exception);
189+
}
190+
}
191+
192+
public override async Task DeleteDirectoryAsync(string virtualPath, CancellationToken cancellationToken = default)
193+
{
194+
throw new NotImplementedException();
195+
}
196+
197+
public override async Task DeleteFileAsync(string virtualPath, CancellationToken cancellationToken = default)
198+
{
199+
throw new NotImplementedException();
200+
}
201+
202+
public override async Task<Stream> ReadFileStreamAsync(string virtualPath, CancellationToken cancellationToken = default)
203+
{
204+
throw new NotImplementedException();
205+
}
206+
207+
public override async Task WriteFileAsync(string virtualPath, Stream contents, bool overwrite = false, CancellationToken cancellationToken = default)
208+
{
209+
throw new NotImplementedException();
210+
}
211+
212+
protected override Exception Exception(Exception exception)
213+
{
214+
if (exception is FileSystemException)
215+
{
216+
return exception;
217+
}
218+
219+
return new AdapterRuntimeException(exception);
220+
}
221+
}
222+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
using SharpGrip.FileSystem.Configuration;
2+
3+
namespace SharpGrip.FileSystem.Adapters.GoogleCloudStorage
4+
{
5+
public class GoogleCloudStorageAdapterConfiguration : AdapterConfiguration
6+
{
7+
}
8+
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
using Google.Apis.Storage.v1.Data;
2+
using SharpGrip.FileSystem.Models;
3+
4+
namespace SharpGrip.FileSystem.Adapters.GoogleCloudStorage
5+
{
6+
public static class ModelFactory
7+
{
8+
public static FileModel CreateFile(Object file, string path, string virtualPath)
9+
{
10+
return new FileModel
11+
{
12+
Name = file.Name,
13+
Path = path,
14+
VirtualPath = virtualPath,
15+
Length = (long?) file.Size,
16+
LastModifiedDateTime = file.UpdatedDateTimeOffset?.DateTime,
17+
CreatedDateTime = file.TimeCreatedDateTimeOffset?.DateTime
18+
};
19+
}
20+
21+
public static DirectoryModel CreateDirectory(string name, string path, string virtualPath)
22+
{
23+
return new DirectoryModel
24+
{
25+
Name = name,
26+
Path = path,
27+
VirtualPath = virtualPath
28+
};
29+
}
30+
31+
public static DirectoryModel CreateDirectory(Object directory, string path, string virtualPath)
32+
{
33+
return new DirectoryModel
34+
{
35+
Name = directory.Name,
36+
Path = path,
37+
VirtualPath = virtualPath,
38+
LastModifiedDateTime = directory.UpdatedDateTimeOffset?.DateTime,
39+
CreatedDateTime = directory.TimeCreatedDateTimeOffset?.DateTime
40+
};
41+
}
42+
}
43+
}

FileSystem.sln

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.Dropbox
1212
EndProject
1313
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.Ftp", "FileSystem.Adapters.Ftp\FileSystem.Adapters.Ftp.csproj", "{ED38402A-3667-4701-A974-4D7710E1544A}"
1414
EndProject
15+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.GoogleCloudStorage", "FileSystem.Adapters.GoogleCloudStorage\FileSystem.Adapters.GoogleCloudStorage.csproj", "{0E6E0F36-55C4-49FF-9298-99D5B3309381}"
16+
EndProject
1517
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.GoogleDrive", "FileSystem.Adapters.GoogleDrive\FileSystem.Adapters.GoogleDrive.csproj", "{CB1F411C-3FB5-4441-9541-423951C17BAF}"
1618
EndProject
1719
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FileSystem.Adapters.MicrosoftOneDrive", "FileSystem.Adapters.MicrosoftOneDrive\FileSystem.Adapters.MicrosoftOneDrive.csproj", "{9955422E-4A50-43CD-BC2B-91E6820F206C}"
@@ -50,6 +52,10 @@ Global
5052
{ED38402A-3667-4701-A974-4D7710E1544A}.Debug|Any CPU.Build.0 = Debug|Any CPU
5153
{ED38402A-3667-4701-A974-4D7710E1544A}.Release|Any CPU.ActiveCfg = Release|Any CPU
5254
{ED38402A-3667-4701-A974-4D7710E1544A}.Release|Any CPU.Build.0 = Release|Any CPU
55+
{0E6E0F36-55C4-49FF-9298-99D5B3309381}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56+
{0E6E0F36-55C4-49FF-9298-99D5B3309381}.Debug|Any CPU.Build.0 = Debug|Any CPU
57+
{0E6E0F36-55C4-49FF-9298-99D5B3309381}.Release|Any CPU.ActiveCfg = Release|Any CPU
58+
{0E6E0F36-55C4-49FF-9298-99D5B3309381}.Release|Any CPU.Build.0 = Release|Any CPU
5359
{CB1F411C-3FB5-4441-9541-423951C17BAF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
5460
{CB1F411C-3FB5-4441-9541-423951C17BAF}.Debug|Any CPU.Build.0 = Debug|Any CPU
5561
{CB1F411C-3FB5-4441-9541-423951C17BAF}.Release|Any CPU.ActiveCfg = Release|Any CPU

FileSystem/FileSystem.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
<PackageId>SharpGrip.FileSystem</PackageId>
1010
<Title>SharpGrip FileSystem</Title>
1111
<Description>SharpGrip FileSystem is a file system abstraction supporting multiple adapters.</Description>
12-
<PackageTags>sharpgrip;file-system;amazon-s3;azure-blob-storage;azure-file-storage;dropbox;ftp;google-drive;microsoft-onedrive;sftp</PackageTags>
12+
<PackageTags>sharpgrip;file-system;amazon-s3;azure-blob-storage;azure-file-storage;dropbox;ftp;google-cloud-storage;google-drive;microsoft-onedrive;sftp</PackageTags>
1313
</PropertyGroup>
1414

1515
<ItemGroup>

FileSystem/src/Adapters/Adapter.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,9 +129,9 @@ public virtual async Task AppendFileAsync(string virtualPath, Stream contents, C
129129
public abstract Task WriteFileAsync(string virtualPath, Stream contents, bool overwrite = false, CancellationToken cancellationToken = default);
130130
protected abstract Exception Exception(Exception exception);
131131

132-
protected string GetPath(string path)
132+
protected string GetPath(string virtualPath)
133133
{
134-
return PathUtilities.GetPath(path, RootPath);
134+
return PathUtilities.GetPath(virtualPath, RootPath);
135135
}
136136

137137
protected string GetVirtualPath(string path)

0 commit comments

Comments
 (0)