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); } }
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}'"); } }