public void OnStreamClosed() { EnsureNotDisposed(); // do not allow to process twice if (isClosed) { return; } // compute hash of last part ComputeCurrentPartHash(); // trim last data file if (currentPart != null) { long lastDataFileLength = currentPart.FileStream.Position; currentPart.FileStream.SetLength(lastDataFileLength); } // dispose all DisposeCurrentPart(); // build result var sequenceInfo = new PackageSequenceInfo(sequenceBaseInfo, totalSize); packageId = new Dto.PackageHashes(version, segmentHashes, cryptoProvider, sequenceInfo); logger.LogDebug($"Closed package data files. Written {SizeFormatter.ToString(totalSize)}. Hash is {packageId.PackageId:s}."); isClosed = true; }
public void Allocate(string path, PackageSequenceInfo sequence, bool overwrite) { if (path == null) { throw new ArgumentNullException(nameof(path)); } if (sequence == null) { throw new ArgumentNullException(nameof(sequence)); } logger.LogInformation($"Allocating {SizeFormatter.ToString(sequence.PackageSize)} for package data in {path}"); Directory.CreateDirectory(path); // check disk space and throw error if not enough var driveInfo = new DriveInfo(Directory.GetDirectoryRoot(path)); long freeSpace = driveInfo.TotalFreeSpace; if (freeSpace < sequence.PackageSize) { throw new InvalidOperationException($"There is not enough disk space on drive {driveInfo.Name}. Free space is {SizeFormatter.ToString(freeSpace)} but required is {SizeFormatter.ToString(sequence.PackageSize)}."); } // prepare parts var sequencer = new PackagePartsSequencer(); var parts = sequencer.GetDataFilesForPackage(path, sequence).ToArray(); if (!overwrite) { // check if already exists foreach (var part in parts) { if (File.Exists(part.Path)) { throw new Exception($"File already exists: {part.Path}"); } } } // allocate foreach (var part in parts) { using (var fs = new FileStream(part.Path, overwrite ? FileMode.OpenOrCreate : FileMode.CreateNew, FileAccess.Write, FileShare.None)) { fs.SetLength(part.PartLength); } } logger.LogDebug("Allocation completed."); }
public void OnStreamPartChange(PackageDataStreamPart oldPart, PackageDataStreamPart newPart) { EnsureNotDisposed(); bool keepSameStream = oldPart != null && newPart != null && oldPart.Path == newPart.Path; // compute hash if (oldPart != null) { ComputeCurrentPartHash(); } if (!keepSameStream) { // close old one if (oldPart != null) { DisposeCurrentPart(); } // open new part if (newPart != null) { logger.LogDebug($"Creating new data file {Path.GetFileName(newPart.Path)}. Already wrote {SizeFormatter.ToString(totalSize)}."); currentPart = new CurrentPart { Part = newPart, FileStream = new FileStream(newPart.Path, FileMode.CreateNew, FileAccess.ReadWrite, FileShare.None) }; currentPart.FileStream.SetLength(newPart.DataFileLength); } } // update current part if (newPart != null) { currentPart.Part = newPart; currentPart.FileStream.Seek(newPart.SegmentOffsetInDataFile, SeekOrigin.Begin); currentPart.HashAlgorithm = cryptoProvider.CreateHashAlgorithm(); currentPart.HashStream = new CryptoStream(currentPart.FileStream, currentPart.HashAlgorithm, CryptoStreamMode.Write, leaveOpen: true); currentPart.Part.Stream = currentPart.HashStream; } }
public override string ToString() => $"\"{Metadata.Name}\" {Id:s} ({SizeFormatter.ToString(Metadata.PackageSize)})";
public void ShouldStringify() { var formatter = new SizeFormatter(10.123); Assert.Equal("10.12 kb", formatter.ToString()); }
public LocalPackageInfo CreatePackageFromFolder(string folderToProcess, string name, MeasureItem writeMeasure) { var operationMeasure = Stopwatch.StartNew(); // storage folder for package EnsurePath(); name = string.IsNullOrWhiteSpace(name) ? FileHelper.GetFileOrDirectoryName(folderToProcess) : name; DirectoryInfo buildDirectory = Directory.CreateDirectory(CreateBuildPath()); logger.LogInformation($"Creating package \"{name}\" from folder: {folderToProcess}"); // create package archive PackageHashes packageHashes; int entriesCount; using (var controller = new CreatePackageDataStreamController(app.Version, app.LoggerFactory, app.Crypto, sequenceForNewPackages, buildDirectory.FullName)) { using (var packageStream = new PackageDataStream(app.LoggerFactory, controller) { Measure = writeMeasure }) { var archive = new PackageArchive(app.CompatibilityChecker, app.MessageSerializer); archive.WriteFromFolder(folderToProcess, packageStream); entriesCount = archive.EntriesCount; } packageHashes = controller.PackageId; } // store package hashes UpdateHashes(packageHashes, directoryPath: buildDirectory.FullName); // store download status PackageSequenceInfo packageSequence = packageHashes.CreatePackageSequence(); PackageDownloadInfo downloadStatus = PackageDownloadInfo.CreateForCreatedPackage(app.Version, packageHashes.PackageId, packageSequence); UpdateDownloadStatus(downloadStatus, directoryPath: buildDirectory.FullName); // store metadata var metadata = new PackageMeta() { Created = DateTimeOffset.Now, Name = name, PackageSize = packageHashes.PackageSize, Version = app.Version, PackageId = packageHashes.PackageId }; UpdateMetadata(metadata, directoryPath: buildDirectory.FullName); // rename folder string packagePath = CreatePackagePath(packageHashes.PackageId); if (Directory.Exists(packagePath)) { throw new InvalidOperationException($"Folder for package {packageHashes.PackageId:s} already exists. {packagePath}"); } Directory.Move(buildDirectory.FullName, packagePath); operationMeasure.Stop(); logger.LogInformation($"Created package \"{packagePath}\":\nHash: {packageHashes.PackageId}\nSize: {SizeFormatter.ToString(packageHashes.PackageSize)}\nFiles and directories: {entriesCount}\nTime: {operationMeasure.Elapsed}"); var reference = new PackageReference(packagePath, packageHashes.PackageId); var result = new LocalPackageInfo(reference, downloadStatus, packageHashes, metadata, packageSequence); return(result); }
public LocalPackageInfo RegisterPackage(PackageHashes hashes, PackageMeta metadata) { if (hashes == null) { throw new ArgumentNullException(nameof(hashes)); } // create directory EnsurePath(); string packagePath = CreatePackagePath(hashes.PackageId); if (Directory.Exists(packagePath)) { logger.LogError("Can't add package with Id {0:s}. This hash already exists in local repository.", hashes.PackageId); throw new InvalidOperationException("Package already exists in local repository."); } Directory.CreateDirectory(packagePath); // store data var packageSequence = hashes.CreatePackageSequence(); PackageDownloadInfo downloadStatus = PackageDownloadInfo.CreateForReadyForDownloadPackage(app.Version, hashes.PackageId, packageSequence); UpdateDownloadStatus(downloadStatus); UpdateHashes(hashes); UpdateMetadata(metadata); // allocate var allocator = new PackageDataAllocator(app.LoggerFactory); allocator.Allocate(packagePath, hashes.CreatePackageSequence(), overwrite: false); // log and build result logger.LogInformation($"New package {hashes.PackageId:s4} added to repository and allocated. Size: {SizeFormatter.ToString(hashes.PackageSize)}"); var reference = new PackageReference(packagePath, hashes.PackageId); var result = new LocalPackageInfo(reference, downloadStatus, hashes, metadata, packageSequence); return(result); }