public void WriteFile(string folderPath, TransportFileDelivery delivery)
        {
            var tf = delivery.TransportFile;

            if (!tf.Verify())
            {
                return;              // Do not write corrupted files
            }
            var directory = !Directory.Exists(folderPath)
                ? Directory.CreateDirectory(folderPath)
                : new DirectoryInfo(folderPath);

            var props = tf.Properties.FromDictionary();

            if (props.IsChunked)
            {
                WriteChunkedFile(directory, delivery, props, false);
            }
            else if (props.IsFileStream)
            {
                WriteFileStream(directory, delivery, false);
            }
            else
            {
                WriteFullFile(directory, delivery, true);
            }
        }
Exemple #2
0
        private void HandleMessage(Action <TransportFileDelivery> callback, Message message)
        {
            var envelope = ReadEnvelope(message);

            if (envelope == null)
            {
                return;
            }

            var properties = ReadTransportFile(envelope);

            if (properties == null)
            {
                SendAcknowledgement(envelope, false);
                return;
            }

            var transportFile = ConvertToTransportFile(properties);
            var isConsistent  = transportFile.Verify();
            var delivery      = new TransportFileDelivery
            {
                IsConsistent  = isConsistent,
                Timestamp     = DateTimeOffset.Now,
                Channel       = message.Topic,
                TransportFile = transportFile
            };

            SendAcknowledgement(envelope, isConsistent);
            callback.Invoke(delivery);
        }
        private static void DeleteExistingFile(TransportFileDelivery delivery, FileSystemInfo directory)
        {
            var fileName = delivery.TransportFile.Name;
            var filePath = Path.Combine(directory.FullName, fileName);

            if (File.Exists(filePath))
            {
                File.Delete(filePath);
            }
        }
        private void WriteFullFile(FileSystemInfo directory, TransportFileDelivery delivery, bool overwrite)
        {
            var fileName = delivery.TransportFile.Name;
            var filePath = Path.Combine(directory.FullName, fileName);

            if (overwrite)
            {
                DeleteExistingFile(delivery, directory);
            }

            using (var fs = File.Open(filePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Read))
                delivery.TransportFile.WriteTo(fs);

            FileReceived?.Invoke(filePath);
        }
        private void WriteChunkedFile(FileSystemInfo directory, TransportFileDelivery delivery, FileTransferProperties props, bool overwrite)
        {
            var fileName = delivery.TransportFile.Name;
            var filePath = GenerateUniqueFileName(Path.Combine(directory.FullName, fileName), overwrite);

            var uniqueTransferId = props.TransferId ?? 0;
            var tmpName          = Path.ChangeExtension(filePath, $".{uniqueTransferId}.temp");

            _log.LogDebug($"Processing chunk no. {props.ChunkNumber} - is last {props.LastChunk}");

            if (filePath == null)
            {
                return;                  // only to make static code analysis happy.
            }
            try
            {
                long maxChunks;
                if (props.LastChunk)
                {
                    maxChunks = props.ChunkNumber + 1;
                }
                else
                {
                    maxChunks  = props.FileSize / props.ChunkSize;
                    maxChunks += props.FileSize % props.ChunkSize != 0 ? 1 : 0;
                }
                var headerSizeInBytes = ChunkedFileHeader.GetHeaderLengthInBytes(maxChunks);

                // Wait here to write to file
                var log = _log; // needed to make static code analysis happy (avoid using variable in and outside synchronization blocks warning)
                lock (string.Intern(tmpName))
                {
                    var tmpFileSize = headerSizeInBytes + props.FileSize;
                    CheckTempFileConsistency(tmpName, uniqueTransferId, tmpFileSize);

                    using (var fs = new FileStream(tmpName, FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read))
                    {
                        using (var mmf = MemoryMappedFile.CreateFromFile(fs, null, tmpFileSize, MemoryMappedFileAccess.ReadWrite, HandleInheritability.Inheritable, false))
                        {
                            var fileHeader = ChunkedFileHeader.ReadFromMemoryMappedFile(mmf, maxChunks);
                            using (var accessor = mmf.CreateViewStream(headerSizeInBytes + props.ChunkOffset, 0))
                            {
                                delivery.TransportFile.WriteTo(accessor);
                            }

                            fileHeader.ChunksReceived[props.ChunkNumber] = true;
                            fileHeader.WriteToMemoryMappedFile(mmf);

                            var isFileComplete = fileHeader.ChunksReceived.All(b => b);
                            if (!isFileComplete)
                            {
                                return;
                            }

                            try
                            {
                                if (overwrite)
                                {
                                    DeleteExistingFile(delivery, directory);
                                }

                                SaveCompletedFileContent(mmf, filePath, headerSizeInBytes, props.FileSize);
                                log.LogInformation($"File written to {filePath}");
                            }
                            catch (IOException e)
                            {
                                log.LogError($"Could not move file from {tmpName} to {filePath} because of {e.Message}");
                                throw;
                            }
                        }
                    }

                    File.Delete(tmpName);
                }

                FileReceived?.Invoke(filePath);
            }
            catch (IOException e)
            {
                _log.LogError($"Could not handle file {tmpName} -> {filePath}: '{e.Message}'");
            }
        }