Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(oss): add Sonatype Nexus integration. #890

Merged
merged 1 commit into from
Oct 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions aspnet-core/LINGYUN.MicroService.All.sln
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Notifications.W
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LINGYUN.Abp.Identity.WeChat.Work", "modules\wechat\LINGYUN.Abp.Identity.WeChat.Work\LINGYUN.Abp.Identity.WeChat.Work.csproj", "{3E32DBDA-1C63-42B4-85D1-E84BBD072D89}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "nexus", "nexus", "{87CE2F0B-0469-4C76-B325-00EA7AB94B99}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.BlobStoring.Nexus", "modules\nexus\LINGYUN.Abp.BlobStoring.Nexus\LINGYUN.Abp.BlobStoring.Nexus.csproj", "{34987F45-8234-428C-AB41-783D42295C32}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.BlobStoring.Nexus.Tests", "tests\LINGYUN.Abp.BlobStoring.Nexus.Tests\LINGYUN.Abp.BlobStoring.Nexus.Tests.csproj", "{227DA969-291B-4749-985C-7A83523B7F53}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.OssManagement.Nexus", "modules\nexus\LINGYUN.Abp.OssManagement.Nexus\LINGYUN.Abp.OssManagement.Nexus.csproj", "{A35E90D3-5375-4BFF-B6E2-24A8CDCBF973}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.Sonatype.Nexus", "modules\nexus\LINGYUN.Abp.Sonatype.Nexus\LINGYUN.Abp.Sonatype.Nexus.csproj", "{CDE35EAE-4B48-40D2-BF57-68EFC5B5A97C}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LINGYUN.Abp.OssManagement.Nexus.Tests", "tests\LINGYUN.Abp.OssManagement.Nexus.Tests\LINGYUN.Abp.OssManagement.Nexus.Tests.csproj", "{F197F8BB-87E3-43FC-92E7-DE8E60EB22E9}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Expand Down Expand Up @@ -1718,6 +1730,26 @@ Global
{3E32DBDA-1C63-42B4-85D1-E84BBD072D89}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E32DBDA-1C63-42B4-85D1-E84BBD072D89}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E32DBDA-1C63-42B4-85D1-E84BBD072D89}.Release|Any CPU.Build.0 = Release|Any CPU
{34987F45-8234-428C-AB41-783D42295C32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{34987F45-8234-428C-AB41-783D42295C32}.Debug|Any CPU.Build.0 = Debug|Any CPU
{34987F45-8234-428C-AB41-783D42295C32}.Release|Any CPU.ActiveCfg = Release|Any CPU
{34987F45-8234-428C-AB41-783D42295C32}.Release|Any CPU.Build.0 = Release|Any CPU
{227DA969-291B-4749-985C-7A83523B7F53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{227DA969-291B-4749-985C-7A83523B7F53}.Debug|Any CPU.Build.0 = Debug|Any CPU
{227DA969-291B-4749-985C-7A83523B7F53}.Release|Any CPU.ActiveCfg = Release|Any CPU
{227DA969-291B-4749-985C-7A83523B7F53}.Release|Any CPU.Build.0 = Release|Any CPU
{A35E90D3-5375-4BFF-B6E2-24A8CDCBF973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A35E90D3-5375-4BFF-B6E2-24A8CDCBF973}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A35E90D3-5375-4BFF-B6E2-24A8CDCBF973}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A35E90D3-5375-4BFF-B6E2-24A8CDCBF973}.Release|Any CPU.Build.0 = Release|Any CPU
{CDE35EAE-4B48-40D2-BF57-68EFC5B5A97C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CDE35EAE-4B48-40D2-BF57-68EFC5B5A97C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CDE35EAE-4B48-40D2-BF57-68EFC5B5A97C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CDE35EAE-4B48-40D2-BF57-68EFC5B5A97C}.Release|Any CPU.Build.0 = Release|Any CPU
{F197F8BB-87E3-43FC-92E7-DE8E60EB22E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F197F8BB-87E3-43FC-92E7-DE8E60EB22E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F197F8BB-87E3-43FC-92E7-DE8E60EB22E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F197F8BB-87E3-43FC-92E7-DE8E60EB22E9}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -2041,6 +2073,12 @@ Global
{2C86306D-D626-41F8-BA3C-5C9B4123CE7D} = {83E698F6-F8CD-4604-AB80-01A203389501}
{2DC43D15-F20F-44EC-B3A3-47BD8BBB50CA} = {DD9BE9E7-F6BF-4869-BCD2-82F5072BDA21}
{3E32DBDA-1C63-42B4-85D1-E84BBD072D89} = {DD9BE9E7-F6BF-4869-BCD2-82F5072BDA21}
{87CE2F0B-0469-4C76-B325-00EA7AB94B99} = {C5CAD011-DF84-4914-939C-0C029DCEF26F}
{34987F45-8234-428C-AB41-783D42295C32} = {87CE2F0B-0469-4C76-B325-00EA7AB94B99}
{227DA969-291B-4749-985C-7A83523B7F53} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F}
{A35E90D3-5375-4BFF-B6E2-24A8CDCBF973} = {B05CB08F-C088-4D6D-97EE-A94A5D1AE4A6}
{CDE35EAE-4B48-40D2-BF57-68EFC5B5A97C} = {87CE2F0B-0469-4C76-B325-00EA7AB94B99}
{F197F8BB-87E3-43FC-92E7-DE8E60EB22E9} = {370D7CD5-1E17-4F3D-BBFA-03429F6D4F2F}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C95FDF91-16F2-4A8B-A4BE-0E62D1B66718}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
<ConfigureAwait ContinueOnCapturedContext="false" />
</Weavers>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="utf-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
<xs:element name="Weavers">
<xs:complexType>
<xs:all>
<xs:element name="ConfigureAwait" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:attribute name="ContinueOnCapturedContext" type="xs:boolean" />
</xs:complexType>
</xs:element>
</xs:all>
<xs:attribute name="VerifyAssembly" type="xs:boolean">
<xs:annotation>
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
<xs:annotation>
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
</xs:annotation>
</xs:attribute>
<xs:attribute name="GenerateXsd" type="xs:boolean">
<xs:annotation>
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
</xs:annotation>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:schema>
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<Import Project="..\..\..\configureawait.props" />
<Import Project="..\..\..\common.props" />

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<RootNamespace />
<Description>Oss对象存储Nexus集成</Description>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Volo.Abp.BlobStoring" Version="$(VoloAbpPackageVersion)" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\LINGYUN.Abp.Sonatype.Nexus\LINGYUN.Abp.Sonatype.Nexus.csproj" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
using LINGYUN.Abp.Sonatype.Nexus;
using Volo.Abp.BlobStoring;
using Volo.Abp.Modularity;

namespace LINGYUN.Abp.BlobStoring.Nexus;

[DependsOn(
typeof(AbpBlobStoringModule),
typeof(AbpSonatypeNexusModule))]
public class AbpBlobStoringNexusModule : AbpModule
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
using System;
using Volo.Abp.BlobStoring;
using Volo.Abp.DependencyInjection;
using Volo.Abp.MultiTenancy;

namespace LINGYUN.Abp.BlobStoring.Nexus;
public class DefaultBlobRawPathCalculator : IBlobRawPathCalculator, ITransientDependency
{
protected ICurrentTenant CurrentTenant { get; }
protected IBlobContainerConfigurationProvider ConfigurationProvider { get; }

public DefaultBlobRawPathCalculator(
ICurrentTenant currentTenant,
IBlobContainerConfigurationProvider configurationProvider)
{
CurrentTenant = currentTenant;
ConfigurationProvider = configurationProvider;
}

public string CalculateGroup(string containerName, string blobName)
{
var blobPath = CalculateBasePath(containerName);

var lastFolderIndex = blobName.LastIndexOf("/");
if (lastFolderIndex > 0)
{
blobPath = blobPath.EnsureEndsWith('/');
blobPath += blobName.Substring(0, lastFolderIndex);
}

return blobPath.EnsureStartsWith('/').RemovePostFix("/");
}

public string CalculateName(string containerName, string blobName, bool replacePath = false)
{
var blobPath = CalculateBasePath(containerName);
blobPath = blobPath.EnsureEndsWith('/');
blobPath += blobName;

if (replacePath)
{
return blobName.Replace(blobPath.RemovePreFix("/"), "").RemovePreFix("/");
}

return blobPath.RemovePreFix("/");
}

protected virtual string CalculateBasePath(string containerName)
{
var configuration = ConfigurationProvider.Get<DefaultContainer>();
var nexusConfiguration = configuration.GetNexusConfiguration();
var blobPath = nexusConfiguration.BasePath;

if (CurrentTenant.Id == null)
{
blobPath = $"{blobPath}/host";
}
else
{
blobPath = $"{blobPath}/tenants/{CurrentTenant.Id.Value.ToString("D")}";
}

if (nexusConfiguration.AppendContainerNameToBasePath)
{
blobPath = $"{blobPath}/{containerName.RemovePreFix("/")}";
}

return blobPath.EnsureStartsWith('/');
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
using Volo.Abp.BlobStoring;

namespace LINGYUN.Abp.BlobStoring.Nexus;
public interface IBlobRawPathCalculator
{
string CalculateGroup(string containerName, string blobName);

string CalculateName(string containerName, string blobName, bool replacePath = false);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using System;
using Volo.Abp.BlobStoring;

namespace LINGYUN.Abp.BlobStoring.Nexus
{
public static class NexusBlobContainerConfigurationExtensions
{
public static NexusBlobProviderConfiguration GetNexusConfiguration(
this BlobContainerConfiguration containerConfiguration)
{
return new NexusBlobProviderConfiguration(containerConfiguration);
}

public static BlobContainerConfiguration UseNexus(
this BlobContainerConfiguration containerConfiguration,
Action<NexusBlobProviderConfiguration> nexusConfigureAction)
{
containerConfiguration.ProviderType = typeof(NexusBlobProvider);
containerConfiguration.NamingNormalizers.TryAdd<NexusBlobNamingNormalizer>();

nexusConfigureAction(new NexusBlobProviderConfiguration(containerConfiguration));

return containerConfiguration;
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Volo.Abp.BlobStoring;
using Volo.Abp.DependencyInjection;

namespace LINGYUN.Abp.BlobStoring.Nexus;
public class NexusBlobNamingNormalizer : IBlobNamingNormalizer, ITransientDependency
{
public virtual string NormalizeContainerName(string containerName)
{
return Normalize(containerName);
}

public virtual string NormalizeBlobName(string blobName)
{
return Normalize(blobName);
}

protected virtual string Normalize(string fileName)
{
return fileName.Replace("\\", "/").Replace("//", "/");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
using LINGYUN.Abp.Sonatype.Nexus.Assets;
using LINGYUN.Abp.Sonatype.Nexus.Components;
using LINGYUN.Abp.Sonatype.Nexus.Search;
using System;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.BlobStoring;
using Volo.Abp.DependencyInjection;

namespace LINGYUN.Abp.BlobStoring.Nexus;
public class NexusBlobProvider : BlobProviderBase, ITransientDependency
{
protected INexusAssetManager NexusAssetManager { get; }
protected INexusComponentManager NexusComponentManager { get; }
protected INexusLookupService NexusLookupService { get; }
protected IBlobRawPathCalculator BlobDirectoryCalculator { get; }

public NexusBlobProvider(
INexusAssetManager nexusAssetManager,
INexusComponentManager nexusComponentManager,
INexusLookupService nexusLookupService,
IBlobRawPathCalculator blobDirectoryCalculator)
{
NexusAssetManager = nexusAssetManager;
NexusComponentManager = nexusComponentManager;
NexusLookupService = nexusLookupService;
BlobDirectoryCalculator = blobDirectoryCalculator;
}

public async override Task<bool> DeleteAsync(BlobProviderDeleteArgs args)
{
var nexusComponent = await GetNexusomponentOrNull(args);
if (nexusComponent == null)
{
return false;
}
return await NexusComponentManager.DeleteAsync(nexusComponent.Id, args.CancellationToken);
}

public async override Task<bool> ExistsAsync(BlobProviderExistsArgs args)
{
var nexusAsset = await GetNexusAssetOrNull(args);
return nexusAsset != null;
}

public async override Task<Stream> GetOrNullAsync(BlobProviderGetArgs args)
{
var nexusAsset = await GetNexusAssetOrNull(args);
if (nexusAsset == null)
{
return null;
}

return await NexusAssetManager.GetContentOrNullAsync(nexusAsset);
}

public async override Task SaveAsync(BlobProviderSaveArgs args)
{
var nexusAsset = await GetNexusAssetOrNull(args);
if (!args.OverrideExisting && nexusAsset != null)
{
throw new BlobAlreadyExistsException($"Saving BLOB '{args.BlobName}' does already exists in the container '{args.ContainerName}'! Set {nameof(args.OverrideExisting)} if it should be overwritten.");
}

var fileBytes = await args.BlobStream.GetAllBytesAsync();
var blobPath = BlobDirectoryCalculator.CalculateGroup(args.ContainerName, args.BlobName);
var blobName = BlobDirectoryCalculator.CalculateName(args.ContainerName, args.BlobName, true);
// blobName = blobName.Replace(blobPath.RemovePreFix("/"), "").RemovePreFix("/");
var asset1 = new Asset(blobName, fileBytes);

var nexusConfiguration = args.Configuration.GetNexusConfiguration();
var repository = nexusConfiguration.Repository;

var nexusRawBlobUploadArgs = new NexusRawBlobUploadArgs(
repository,
blobPath,
asset1);

await NexusComponentManager.UploadAsync(nexusRawBlobUploadArgs, args.CancellationToken);
}

protected async virtual Task<NexusAsset> GetNexusAssetOrNull(BlobProviderArgs args)
{
var nexusConfiguration = args.Configuration.GetNexusConfiguration();
var blobPath = BlobDirectoryCalculator.CalculateGroup(args.ContainerName, args.BlobName);
var blobName = BlobDirectoryCalculator.CalculateName(args.ContainerName, args.BlobName);
var nexusSearchArgs = new NexusSearchArgs(
nexusConfiguration.Repository,
blobPath,
blobName);

var nexusAssetListResult = await NexusLookupService.ListAssetAsync(nexusSearchArgs, args.CancellationToken);
var nexusAsset = nexusAssetListResult.Items.FirstOrDefault();

return nexusAsset;
}

protected async virtual Task<NexusComponent> GetNexusomponentOrNull(BlobProviderArgs args)
{
var nexusConfiguration = args.Configuration.GetNexusConfiguration();
var blobPath = BlobDirectoryCalculator.CalculateGroup(args.ContainerName, args.BlobName);
var blobName = BlobDirectoryCalculator.CalculateName(args.ContainerName, args.BlobName);
var nexusSearchArgs = new NexusSearchArgs(
nexusConfiguration.Repository,
blobPath,
blobName);

var nexusComponentResult = await NexusLookupService.ListComponentAsync(nexusSearchArgs, args.CancellationToken);
var nexusComponent = nexusComponentResult.Items.FirstOrDefault();

return nexusComponent;
}
}
Loading