Пример #1
0
        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;
        }
Пример #2
0
        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.");
        }
Пример #3
0
        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;
            }
        }
Пример #4
0
 public override string ToString() => $"\"{Metadata.Name}\" {Id:s} ({SizeFormatter.ToString(Metadata.PackageSize)})";
Пример #5
0
        public void ShouldStringify()
        {
            var formatter = new SizeFormatter(10.123);

            Assert.Equal("10.12 kb", formatter.ToString());
        }
Пример #6
0
        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);
        }
Пример #7
0
        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);
        }