diff --git a/README.md b/README.md index 7da81c140920962b6df6faceba2a4ab4a5062f4a..e1c42f10379ac38ed06dfa23b7807eb84ff0d84a 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ The allows to zip a folder and/or upload a whole stream in chunks to a S3 object For example: ``` -var s3 = new S3Zip(s3MultipartStreamConfiguration); -s3.ZipAndUploadFolder(@"c:\temp\test", "Test.zip"); +var zipUtilities = new ZipUtilities(_s3MultipartStreamConfiguration); +zipUtilities.ZipAndUploadFolder(@"c:\temp\test", "test.zip"); ``` -A zip file of the folder will be in S3 under the key Test.zip. \ No newline at end of file +A zip file of the folder will be in S3 under the key test.zip. \ No newline at end of file diff --git a/docs/home.md b/docs/home.md index 7da81c140920962b6df6faceba2a4ab4a5062f4a..e1c42f10379ac38ed06dfa23b7807eb84ff0d84a 100644 --- a/docs/home.md +++ b/docs/home.md @@ -4,8 +4,8 @@ The allows to zip a folder and/or upload a whole stream in chunks to a S3 object For example: ``` -var s3 = new S3Zip(s3MultipartStreamConfiguration); -s3.ZipAndUploadFolder(@"c:\temp\test", "Test.zip"); +var zipUtilities = new ZipUtilities(_s3MultipartStreamConfiguration); +zipUtilities.ZipAndUploadFolder(@"c:\temp\test", "test.zip"); ``` -A zip file of the folder will be in S3 under the key Test.zip. \ No newline at end of file +A zip file of the folder will be in S3 under the key test.zip. \ No newline at end of file diff --git a/src/cs-S3Zip.Tests/Properties/AssemblyInfo.cs b/src/cs-S3Zip.Tests/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..e6da98f0c71e9aa38cdecd05afd8c134120ffa1e --- /dev/null +++ b/src/cs-S3Zip.Tests/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("cs-S3Zip.Tests")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("cs-S3Zip.Tests")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("6b58eb5e-d857-464b-8174-c17375bae1cf")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/cs-S3Zip.Tests/S3ZipTests.cs b/src/cs-S3Zip.Tests/S3ZipTests.cs new file mode 100644 index 0000000000000000000000000000000000000000..df276e11a1333dfce1d0607b2210e7ab334b962c --- /dev/null +++ b/src/cs-S3Zip.Tests/S3ZipTests.cs @@ -0,0 +1,107 @@ + +using Amazon.S3; +using Amazon.S3.Model; +using NUnit.Framework; +using System; +using System.IO; +using System.Linq; +using System.Security.Cryptography; + +namespace coscine.cs_S3Zip.Tests +{ + [TestFixture] + public class S3ZipTests + { + private readonly S3MultipartStreamConfiguration _s3MultipartStreamConfiguration; + + private readonly int ONE_MB; + + public S3ZipTests() + { + var accessKey = Environment.GetEnvironmentVariable("S3_ACCESS_KEY", EnvironmentVariableTarget.Process); + var secretKey = Environment.GetEnvironmentVariable("S3_SECRET_KEY", EnvironmentVariableTarget.Process); + + ONE_MB = (int)Math.Pow(2, 20); + + _s3MultipartStreamConfiguration = new S3MultipartStreamConfiguration + { + AccessKey = accessKey, + SecretKey = secretKey, + BucketName = "PITLABTTEST", + AmazonS3Config = new AmazonS3Config + { + ServiceURL = "https://s3.rwth-aachen.de/", + ForcePathStyle = true + } + }; + } + + [TestCase(110, 50)] + [TestCase(110, 5)] + [TestCase(30, 50)] + [TestCase(30, 5)] + public void S3StreamTest(int length, int chunkSize) + { + var key = "S3StreamTest.txt"; + var chars = "$%#@!*abcdefghijklmnopqrstuvwxyz1234567890?;:ABCDEFGHIJKLMNOPQRSTUVWXYZ^&".ToCharArray(); + var seed = DateTime.Now.Millisecond; + var random = new Random(seed); + var randomBuffer = new byte[ONE_MB]; + + var oldChunkSize = _s3MultipartStreamConfiguration.ChunckSize; + _s3MultipartStreamConfiguration.ChunckSize = chunkSize * ONE_MB; + + using (var s3Stream = new S3MultipartStream(key, _s3MultipartStreamConfiguration)) + { + for (int i = 0; i < length; i++) + { + FillArrayWithRandomChars(randomBuffer, randomBuffer.Length, chars, random); + s3Stream.Write(randomBuffer, 0, ONE_MB); + } + } + + var request = new GetObjectRequest + { + BucketName = _s3MultipartStreamConfiguration.BucketName, + Key = key + }; + + // reset the random number generator + random = new Random(seed); + + using (var client = new AmazonS3Client(_s3MultipartStreamConfiguration.AccessKey, _s3MultipartStreamConfiguration.SecretKey, _s3MultipartStreamConfiguration.AmazonS3Config)) + { + var buffer = new byte[ONE_MB]; + using (var response = client.GetObject(request)) + { + // Was request successfull? + Assert.IsTrue(response.HttpStatusCode == System.Net.HttpStatusCode.OK); + // Has the correct length? + Assert.IsTrue(response.ContentLength == length * ONE_MB); + + using (var responseStream = response.ResponseStream) + { + int alreadyRead = 0; + for (int i = 0; i < length; i++) + { + int read = responseStream.Read(buffer, 0, buffer.Length); + FillArrayWithRandomChars(randomBuffer, read, chars, random); + // check if the data is equal to the previously generated one. + Assert.IsTrue(Enumerable.SequenceEqual(randomBuffer.Take(read), buffer.Take(read))); + alreadyRead += read; + } + } + } + } + _s3MultipartStreamConfiguration.ChunckSize = oldChunkSize; + } + + private void FillArrayWithRandomChars(byte[] randomBuffer, int length, char[] chars, Random random) + { + for (int i = 0; i < length; i++) + { + randomBuffer[i] = (byte)chars[random.Next(chars.Length)]; + } + } + } +} diff --git a/src/cs-S3Zip.Tests/cs-S3Zip.Tests.csproj b/src/cs-S3Zip.Tests/cs-S3Zip.Tests.csproj new file mode 100644 index 0000000000000000000000000000000000000000..2cfe828b83a8aae8cc8c24ac945b09aa16437566 --- /dev/null +++ b/src/cs-S3Zip.Tests/cs-S3Zip.Tests.csproj @@ -0,0 +1,73 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="..\packages\NUnit3TestAdapter.3.13.0\build\net35\NUnit3TestAdapter.props" Condition="Exists('..\packages\NUnit3TestAdapter.3.13.0\build\net35\NUnit3TestAdapter.props')" /> + <Import Project="..\packages\NUnit.3.11.0\build\NUnit.props" Condition="Exists('..\packages\NUnit.3.11.0\build\NUnit.props')" /> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{6B58EB5E-D857-464B-8174-C17375BAE1CF}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>coscine.cs_S3Zip.Tests</RootNamespace> + <AssemblyName>cs-S3Zip.Tests</AssemblyName> + <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <Deterministic>true</Deterministic> + <NuGetPackageImportStamp> + </NuGetPackageImportStamp> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604" /> + <Reference Include="AWSSDK.S3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604" /> + <Reference Include="nunit.framework, Version=3.11.0.0, Culture=neutral, PublicKeyToken=2638cd05610744eb, processorArchitecture=MSIL"> + <HintPath>..\packages\NUnit.3.11.0\lib\net45\nunit.framework.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="S3ZipTests.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\cs-S3Zip\cs-S3Zip.csproj"> + <Project>{7AC0CBDF-046B-496E-931B-776678098C7E}</Project> + <Name>cs-S3Zip</Name> + </ProjectReference> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> + <Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild"> + <PropertyGroup> + <ErrorText>This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}.</ErrorText> + </PropertyGroup> + <Error Condition="!Exists('..\packages\NUnit.3.11.0\build\NUnit.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit.3.11.0\build\NUnit.props'))" /> + <Error Condition="!Exists('..\packages\NUnit3TestAdapter.3.13.0\build\net35\NUnit3TestAdapter.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\NUnit3TestAdapter.3.13.0\build\net35\NUnit3TestAdapter.props'))" /> + </Target> +</Project> \ No newline at end of file diff --git a/src/cs-S3Zip.Tests/packages.config b/src/cs-S3Zip.Tests/packages.config new file mode 100644 index 0000000000000000000000000000000000000000..cde7f3d9f886b890b8e3765997d986994e6497cb --- /dev/null +++ b/src/cs-S3Zip.Tests/packages.config @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="NUnit" version="3.11.0" targetFramework="net472" /> + <package id="NUnit3TestAdapter" version="3.13.0" targetFramework="net472" /> +</packages> \ No newline at end of file diff --git a/src/cs-S3Zip.sln b/src/cs-S3Zip.sln new file mode 100644 index 0000000000000000000000000000000000000000..21c63b117459395eb48c0c37418b9d10df00fd64 --- /dev/null +++ b/src/cs-S3Zip.sln @@ -0,0 +1,31 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.28803.156 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cs-S3Zip", "cs-S3Zip\cs-S3Zip.csproj", "{7AC0CBDF-046B-496E-931B-776678098C7E}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "cs-S3Zip.Tests", "cs-S3Zip.Tests\cs-S3Zip.Tests.csproj", "{6B58EB5E-D857-464B-8174-C17375BAE1CF}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {7AC0CBDF-046B-496E-931B-776678098C7E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {7AC0CBDF-046B-496E-931B-776678098C7E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {7AC0CBDF-046B-496E-931B-776678098C7E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {7AC0CBDF-046B-496E-931B-776678098C7E}.Release|Any CPU.Build.0 = Release|Any CPU + {6B58EB5E-D857-464B-8174-C17375BAE1CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6B58EB5E-D857-464B-8174-C17375BAE1CF}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6B58EB5E-D857-464B-8174-C17375BAE1CF}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6B58EB5E-D857-464B-8174-C17375BAE1CF}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {CB4D8BFF-53DB-45F3-9A1B-8572F8A2D443} + EndGlobalSection +EndGlobal diff --git a/src/cs-S3Zip/Properties/AssemblyInfo.cs b/src/cs-S3Zip/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000000000000000000000000000000000..74d2e66ba90e3bc1726c003bcdc711e847fdf912 --- /dev/null +++ b/src/cs-S3Zip/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("cs-S3Zip")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("cs-S3Zip")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7ac0cbdf-046b-496e-931b-776678098c7e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/src/cs-S3Zip/S3MultipartStream.cs b/src/cs-S3Zip/S3MultipartStream.cs new file mode 100644 index 0000000000000000000000000000000000000000..90f378ceadc59a71bede44bfc99c8458acb91458 --- /dev/null +++ b/src/cs-S3Zip/S3MultipartStream.cs @@ -0,0 +1,158 @@ +using Amazon.S3; +using Amazon.S3.Model; +using System; +using System.Collections.Generic; +using System.IO; + +namespace coscine.cs_S3Zip +{ + public class S3MultipartStream : Stream + { + private readonly Stream _internalStream; + private readonly InitiateMultipartUploadResponse _initiateMultipartUploadResponse; + private readonly List<UploadPartResponse> _uploadPartResponses; + private int _part; + private int _length; + private int _position; + + public S3MultipartStream(string key, S3MultipartStreamConfiguration s3MultipartStreamConfiguration, Stream internalStream) + { + S3MultipartStreamConfiguration = s3MultipartStreamConfiguration; + + _internalStream = internalStream; + _uploadPartResponses = new List<UploadPartResponse>(); + _part = 0; + _length = 0; + _position = 0; + + Key = key; + + var initiateRequest = new InitiateMultipartUploadRequest + { + BucketName = S3MultipartStreamConfiguration.BucketName, + Key = key + }; + + using (var client = new AmazonS3Client(S3MultipartStreamConfiguration.AccessKey, S3MultipartStreamConfiguration.SecretKey, S3MultipartStreamConfiguration.AmazonS3Config)) + { + _initiateMultipartUploadResponse = client.InitiateMultipartUpload(initiateRequest); + } + } + + public S3MultipartStream(string key, S3MultipartStreamConfiguration s3MultipartStreamConfiguration) : this(key, s3MultipartStreamConfiguration, new MemoryStream(s3MultipartStreamConfiguration.ChunckSize)) + { + + } + + public string Key { get; } + + public S3MultipartStreamConfiguration S3MultipartStreamConfiguration { get; set; } + + public override bool CanRead => false; + + public override bool CanSeek => false; + + public override bool CanWrite => true; + + public override long Length => _length; + + public override long Position { get => _position; set => throw new NotImplementedException(); } + + public override void Flush() + { + _internalStream.Flush(); + } + + public override int Read(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } + + public override long Seek(long offset, SeekOrigin origin) + { + throw new NotImplementedException(); + } + + public override void SetLength(long value) + { + throw new NotImplementedException(); + } + + public override void Write(byte[] buffer, int offset, int count) + { + int written = 0; + while (written < count) + { + if (count - written + _internalStream.Length <= S3MultipartStreamConfiguration.ChunckSize) + { + _internalStream.Write(buffer, offset + written, count - written); + break; + } + else + { + int toBeWritten = S3MultipartStreamConfiguration.ChunckSize - (int)_internalStream.Length; + _internalStream.Write(buffer, offset + written, toBeWritten); + written += toBeWritten; + UploadPart(); + + // resets stream + _internalStream.SetLength(0); + } + } + + _length += count; + _position += count; + } + + private void UploadPart() + { + using (var client = new AmazonS3Client(S3MultipartStreamConfiguration.AccessKey, S3MultipartStreamConfiguration.SecretKey, S3MultipartStreamConfiguration.AmazonS3Config)) + { + _internalStream.Position = 0; + + var uploadPartRequest = new UploadPartRequest + { + BucketName = S3MultipartStreamConfiguration.BucketName, + Key = Key, + UploadId = _initiateMultipartUploadResponse.UploadId, + PartNumber = _part + 1, + PartSize = _internalStream.Length, + InputStream = _internalStream + }; + + _uploadPartResponses.Add(client.UploadPart(uploadPartRequest)); + _part++; + } + } + + private void FinalizeS3MultipartUpload() + { + var completeRequest = new CompleteMultipartUploadRequest + { + BucketName = S3MultipartStreamConfiguration.BucketName, + Key = Key, + UploadId = _initiateMultipartUploadResponse.UploadId + }; + + completeRequest.AddPartETags(_uploadPartResponses); + + using (var client = new AmazonS3Client(S3MultipartStreamConfiguration.AccessKey, S3MultipartStreamConfiguration.SecretKey, S3MultipartStreamConfiguration.AmazonS3Config)) + { + client.CompleteMultipartUpload(completeRequest); + } + } + + // Finalize on stream close clall. + public override void Close() + { + if(_internalStream.Length > 0) + { + UploadPart(); + } + + FinalizeS3MultipartUpload(); + + _internalStream.Close(); + } + } +} diff --git a/src/cs-S3Zip/S3MultipartStreamConfiguration.cs b/src/cs-S3Zip/S3MultipartStreamConfiguration.cs new file mode 100644 index 0000000000000000000000000000000000000000..8c1119f52e588b4a73fbc147c2c8e1beeb824436 --- /dev/null +++ b/src/cs-S3Zip/S3MultipartStreamConfiguration.cs @@ -0,0 +1,18 @@ +using Amazon.S3; +using System; + +namespace coscine.cs_S3Zip +{ + public class S3MultipartStreamConfiguration + { + public string AccessKey { get; set; } + + public string SecretKey { get; set; } + + public string BucketName { get; set; } + + public AmazonS3Config AmazonS3Config { get; set; } + + public int ChunckSize { get; set; } = 50 * (int)Math.Pow(2, 20); + } +} diff --git a/src/cs-S3Zip/ZipUtilities.cs b/src/cs-S3Zip/ZipUtilities.cs new file mode 100644 index 0000000000000000000000000000000000000000..b717ce7c32c110b2c8e159f4f5de12cf3c7876ee --- /dev/null +++ b/src/cs-S3Zip/ZipUtilities.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; + +namespace coscine.cs_S3Zip +{ + public class ZipUtilities + { + public S3MultipartStreamConfiguration S3ZipConfiguration { get; set; } + + public ZipUtilities(S3MultipartStreamConfiguration s3ZipConfiguration) + { + S3ZipConfiguration = s3ZipConfiguration; + } + + public void ZipFolder(string path, ZipArchive zipArchive) + { + ZipFolder(new DirectoryInfo(path), zipArchive); + } + + public void ZipFolder(DirectoryInfo directoryInfo, ZipArchive zipArchive) + { + var prefixLength = directoryInfo.FullName.EndsWith(@"\") ? directoryInfo.FullName.Length : directoryInfo.FullName.Length + 1; + ZipFiles(directoryInfo.GetFiles("*", SearchOption.AllDirectories), prefixLength, zipArchive); + } + + public void ZipFiles(IEnumerable<FileInfo> files, int prefixLength, ZipArchive zipArchive) + { + foreach (var file in files) + { + // cut off parent directory path + var fileEntry = zipArchive.CreateEntry(file.FullName.Substring(prefixLength)); + using (var fileStream = file.OpenRead()) + { + ZipStream(fileStream, fileEntry); + } + } + } + + public void ZipStream(Stream stream, ZipArchiveEntry fileEntry) + { + using (var entryStream = fileEntry.Open()) + { + stream.CopyTo(entryStream); + } + } + + + public void ZipAndUploadFolder(string path) + { + ZipAndUploadFolder(new DirectoryInfo(path)); + } + + public void ZipAndUploadFolder(DirectoryInfo directoryInfo) + { + ZipAndUploadFolder(directoryInfo, directoryInfo.Name); + } + + public void ZipAndUploadFolder(string path, string key) + { + ZipAndUploadFolder(new DirectoryInfo(path), key); + } + + public void ZipAndUploadFolder(DirectoryInfo directoryInfo, string key) + { + using (var s3Stream = new S3MultipartStream(key, S3ZipConfiguration)) + { + using (var archive = new ZipArchive(s3Stream, ZipArchiveMode.Create, true)) + { + ZipFolder(directoryInfo, archive); + } + } + } + } +} diff --git a/src/cs-S3Zip/cs-S3Zip.csproj b/src/cs-S3Zip/cs-S3Zip.csproj new file mode 100644 index 0000000000000000000000000000000000000000..49c61bf658d90b6c90332cf6b346e9fb545f1cc6 --- /dev/null +++ b/src/cs-S3Zip/cs-S3Zip.csproj @@ -0,0 +1,63 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <ProjectGuid>{7AC0CBDF-046B-496E-931B-776678098C7E}</ProjectGuid> + <OutputType>Library</OutputType> + <AppDesignerFolder>Properties</AppDesignerFolder> + <RootNamespace>coscine.cs_S3Zip</RootNamespace> + <AssemblyName>cs-S3Zip</AssemblyName> + <TargetFrameworkVersion>v4.7.2</TargetFrameworkVersion> + <FileAlignment>512</FileAlignment> + <Deterministic>true</Deterministic> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + <DebugSymbols>true</DebugSymbols> + <DebugType>full</DebugType> + <Optimize>false</Optimize> + <OutputPath>bin\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + <DebugType>pdbonly</DebugType> + <Optimize>true</Optimize> + <OutputPath>bin\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <ErrorReport>prompt</ErrorReport> + <WarningLevel>4</WarningLevel> + </PropertyGroup> + <ItemGroup> + <Reference Include="AWSSDK.Core, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL"> + <HintPath>..\packages\AWSSDK.Core.3.3.101.1\lib\net45\AWSSDK.Core.dll</HintPath> + </Reference> + <Reference Include="AWSSDK.S3, Version=3.3.0.0, Culture=neutral, PublicKeyToken=885c28607f98e604, processorArchitecture=MSIL"> + <HintPath>..\packages\AWSSDK.S3.3.3.101.8\lib\net45\AWSSDK.S3.dll</HintPath> + </Reference> + <Reference Include="System" /> + <Reference Include="System.Core" /> + <Reference Include="System.IO.Compression" /> + <Reference Include="System.Xml.Linq" /> + <Reference Include="System.Data.DataSetExtensions" /> + <Reference Include="Microsoft.CSharp" /> + <Reference Include="System.Data" /> + <Reference Include="System.Net.Http" /> + <Reference Include="System.Xml" /> + </ItemGroup> + <ItemGroup> + <Compile Include="S3MultipartStream.cs" /> + <Compile Include="ZipUtilities.cs" /> + <Compile Include="Properties\AssemblyInfo.cs" /> + <Compile Include="S3MultipartStreamConfiguration.cs" /> + </ItemGroup> + <ItemGroup> + <None Include="packages.config" /> + </ItemGroup> + <ItemGroup> + <Analyzer Include="..\packages\AWSSDK.S3.3.3.101.8\analyzers\dotnet\cs\AWSSDK.S3.CodeAnalysis.dll" /> + </ItemGroup> + <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> +</Project> \ No newline at end of file diff --git a/src/cs-S3Zip/packages.config b/src/cs-S3Zip/packages.config new file mode 100644 index 0000000000000000000000000000000000000000..ee7c9340b5b6d011342e80f5d0d1dce5526425f3 --- /dev/null +++ b/src/cs-S3Zip/packages.config @@ -0,0 +1,5 @@ +<?xml version="1.0" encoding="utf-8"?> +<packages> + <package id="AWSSDK.Core" version="3.3.101.1" targetFramework="net472" /> + <package id="AWSSDK.S3" version="3.3.101.8" targetFramework="net472" /> +</packages> \ No newline at end of file