Skip to content

Commit

Permalink
Add Alibaba Cloud (Aliyun) OSS storage (loic-sharma#459)
Browse files Browse the repository at this point in the history
  • Loading branch information
chadzhao authored Feb 6, 2020
1 parent e977af7 commit 00466c3
Show file tree
Hide file tree
Showing 11 changed files with 214 additions and 1 deletion.
7 changes: 7 additions & 0 deletions BaGet.sln
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{DDEC
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BaGet.Protocol.Samples.Tests", "samples\BaGet.Protocol.Samples.Tests.csproj", "{16B0D424-BB2F-4C0C-90B0-4F7955326ADF}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BaGet.Aliyun", "src\BaGet.Aliyun\BaGet.Aliyun.csproj", "{9F7C4F38-D598-42D9-A9F8-962490483B18}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -112,6 +114,10 @@ Global
{16B0D424-BB2F-4C0C-90B0-4F7955326ADF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{16B0D424-BB2F-4C0C-90B0-4F7955326ADF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{16B0D424-BB2F-4C0C-90B0-4F7955326ADF}.Release|Any CPU.Build.0 = Release|Any CPU
{9F7C4F38-D598-42D9-A9F8-962490483B18}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9F7C4F38-D598-42D9-A9F8-962490483B18}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9F7C4F38-D598-42D9-A9F8-962490483B18}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9F7C4F38-D598-42D9-A9F8-962490483B18}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand All @@ -132,6 +138,7 @@ Global
{F48F201A-4DEE-4D5B-9C0B-59490FE942FA} = {26A0B557-53FB-4B9A-94C4-BCCF1BDCB0CC}
{D7D60BA0-FF7F-4B37-815C-74D487C5176E} = {26A0B557-53FB-4B9A-94C4-BCCF1BDCB0CC}
{16B0D424-BB2F-4C0C-90B0-4F7955326ADF} = {DDEC0736-8169-4834-815E-B78E7CE612A4}
{9F7C4F38-D598-42D9-A9F8-962490483B18} = {26A0B557-53FB-4B9A-94C4-BCCF1BDCB0CC}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {1423C027-2C90-417F-8629-2A4CF107C055}
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ You can run BaGet on your preferred platform:
* [Azure](quickstart/azure.md)
* [AWS](quickstart/aws.md)
* [Google Cloud](quickstart/gcp.md)
* [Alibaba Cloud(Aliyun)](quickstart/aliyun.md)

## BaGet SDK

Expand Down
28 changes: 28 additions & 0 deletions docs/quickstart/aliyun.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
# Use Alibaba (Aliyun) Object Storage Service

You can store packages to [Alibaba(Aliyun) OSS](https://www.alibabacloud.com/product/oss).

## Configure BaGet

You can modify BaGet's configurations by editing the `appsettings.json` file. For the full list of configurations, please refer to [BaGet's configuration](../configuration.md) guide.

### Aliyun OSS Storage

Update the `appsettings.json` file:

```json
{
...

"Storage": {
"Type": "AliyunOss",
"Endpoint": "oss-us-west-1.aliyuncs.com",
"Bucket": "foo",
"AccessKey": "",
"AccessKeySecret": "",
"Prefix": "lib/baget" // optional
},

...
}
```
94 changes: 94 additions & 0 deletions src/BaGet.Aliyun/AliyunStorageService.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Aliyun.OSS;
using BaGet.Aliyun.Configuration;
using BaGet.Core;
using Microsoft.Extensions.Options;

namespace BaGet.Aliyun
{
public class AliyunStorageService : IStorageService
{
private const string Separator = "/";
private readonly string _bucket;
private readonly string _prefix;
private readonly OssClient _client;

public AliyunStorageService(IOptionsSnapshot<AliyunStorageOptions> options, OssClient client)
{
if (options == null)
throw new ArgumentNullException(nameof(options));

_bucket = options.Value.Bucket;
_prefix = options.Value.Prefix;
_client = client ?? throw new ArgumentNullException(nameof(client));

if (!string.IsNullOrEmpty(_prefix) && !_prefix.EndsWith(Separator))
_prefix += Separator;
}

private string PrepareKey(string path)
{
return _prefix + path.Replace("\\", Separator);
}

public async Task<Stream> GetAsync(string path, CancellationToken cancellationToken = default)
{
try
{
var ossObject = await Task.Factory.FromAsync(_client.BeginGetObject, _client.EndGetObject, _bucket, PrepareKey(path), null);

return ossObject.ResponseStream;
}
catch (Exception)
{
// TODO
throw;
}
}

public Task<Uri> GetDownloadUriAsync(string path, CancellationToken cancellationToken = default)
{
var uri = _client.GeneratePresignedUri(_bucket, PrepareKey(path));

return Task.FromResult(uri);
}

public async Task<StoragePutResult> PutAsync(string path, Stream content, string contentType, CancellationToken cancellationToken = default)
{
// TODO: Uploads should be idempotent. This should fail if and only if the blob
// already exists but has different content.

var metadata = new ObjectMetadata
{
ContentType = contentType,
};

var putResult = await Task<PutObjectResult>.Factory.FromAsync(_client.BeginPutObject, _client.EndPutObject, _bucket, PrepareKey(path), content, metadata);

switch (putResult.HttpStatusCode)
{
case System.Net.HttpStatusCode.OK:
return StoragePutResult.Success;

// TODO: check sdk documents
//case System.Net.HttpStatusCode.Conflict:
// return StoragePutResult.Conflict;

//case System.Net.HttpStatusCode.Found:
// return StoragePutResult.AlreadyExists;

default:
return StoragePutResult.Success;
}
}

public Task DeleteAsync(string path, CancellationToken cancellationToken = default)
{
_client.DeleteObject(_bucket, PrepareKey(path));
return Task.CompletedTask;
}
}
}
16 changes: 16 additions & 0 deletions src/BaGet.Aliyun/BaGet.Aliyun.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<PackageTags>NuGet;Alibaba;Cloud</PackageTags>
<Description>The libraries to host BaGet on Alibaba Cloud (Aliyun).</Description>
<TargetFramework>netstandard2.0</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Aliyun.OSS.SDK.NetCore" Version="2.9.1" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BaGet.Core\BaGet.Core.csproj" />
</ItemGroup>

</Project>
22 changes: 22 additions & 0 deletions src/BaGet.Aliyun/Configuration/AliyunStorageOptions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
using System.ComponentModel.DataAnnotations;
using BaGet.Core;

namespace BaGet.Aliyun.Configuration
{
public class AliyunStorageOptions
{
[Required]
public string AccessKey { get; set; }

[Required]
public string AccessKeySecret { get; set; }

[Required]
public string Endpoint { get; set; }

[Required]
public string Bucket { get; set; }

public string Prefix { get; set; }
}
}
25 changes: 25 additions & 0 deletions src/BaGet.Aliyun/Extensions/ServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
using System;
using Aliyun.OSS;
using BaGet.Aliyun.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;

namespace BaGet.Aliyun.Extensions
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddAliyunStorageService(this IServiceCollection services)
{
services.AddSingleton(provider =>
{
var options = provider.GetRequiredService<IOptions<AliyunStorageOptions>>().Value;

return new OssClient(options.Endpoint, options.AccessKey, options.AccessKeySecret);
});

services.AddTransient<AliyunStorageService>();

return services;
}
}
}
1 change: 1 addition & 0 deletions src/BaGet.Core/Configuration/StorageOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,6 @@ public enum StorageType
AwsS3 = 2,
GoogleCloud = 3,
Null = 4,
AliyunOss = 5,
}
}
1 change: 1 addition & 0 deletions src/BaGet/BaGet.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\BaGet.Aliyun\BaGet.Aliyun.csproj" />
<ProjectReference Include="..\BaGet.Aws\BaGet.Aws.csproj" />
<ProjectReference Include="..\BaGet.Azure\BaGet.Azure.csproj" />
<ProjectReference Include="..\BaGet.Core\BaGet.Core.csproj" />
Expand Down
17 changes: 17 additions & 0 deletions src/BaGet/Extensions/IServiceCollectionExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
using System.Net;
using System.Net.Http;
using System.Reflection;
using BaGet.Aliyun;
using BaGet.Aliyun.Configuration;
using BaGet.Aliyun.Extensions;
using BaGet.Aws;
using BaGet.Aws.Configuration;
using BaGet.Aws.Extensions;
Expand Down Expand Up @@ -43,6 +46,7 @@ public static IServiceCollection ConfigureBaGet(
services.ConfigureAzure(configuration);
services.ConfigureAws(configuration);
services.ConfigureGcp(configuration);
services.ConfigureAliyunOSS(configuration);

if (httpServices)
{
Expand Down Expand Up @@ -170,6 +174,15 @@ public static IServiceCollection ConfigureAws(
return services;
}

public static IServiceCollection ConfigureAliyunOSS(
this IServiceCollection services,
IConfiguration configuration)
{
services.ConfigureAndValidate<AliyunStorageOptions>(configuration.GetSection(nameof(BaGetOptions.Storage)));

return services;
}

public static IServiceCollection ConfigureGcp(
this IServiceCollection services,
IConfiguration configuration)
Expand All @@ -190,6 +203,7 @@ public static IServiceCollection AddStorageProviders(this IServiceCollection ser
services.AddBlobStorageService();
services.AddS3StorageService();
services.AddGoogleCloudStorageService();
services.AddAliyunStorageService();

services.AddTransient<IStorageService>(provider =>
{
Expand All @@ -212,6 +226,9 @@ public static IServiceCollection AddStorageProviders(this IServiceCollection ser
case StorageType.Null:
return provider.GetRequiredService<NullStorageService>();

case StorageType.AliyunOss:
return provider.GetRequiredService<AliyunStorageService>();

default:
throw new InvalidOperationException(
$"Unsupported storage service: {options.Value.Storage.Type}");
Expand Down
3 changes: 2 additions & 1 deletion src/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,5 @@ These folders contain cloud-specific components of BaGet:

* `BaGet.Azure` - BaGet's Azure provider
* `BaGet.Aws` - BaGet's Amazon Web Services provider
* `BaGet.Gcp` - BaGet's Google Cloud Platform provider
* `BaGet.Gcp` - BaGet's Google Cloud Platform provider
* `BaGet.Aliyun` - BaGet's Alibaba Cloud(Aliyun) provider

0 comments on commit 00466c3

Please sign in to comment.