/// <inheritdoc /> public async Task <long> AppendDataAsync(string fileId, Stream stream, CancellationToken cancellationToken) { var internalFileId = new InternalFileId(fileId); long bytesWritten = 0; var uploadLength = await GetUploadLengthAsync(fileId, cancellationToken); using (var file = _fileRepFactory.Data(internalFileId).GetStream(FileMode.Append, FileAccess.Write, FileShare.None)) { var fileLength = file.Length; if (uploadLength == fileLength) { return(0); } var chunkStart = _fileRepFactory.ChunkStartPosition(internalFileId); var chunkComplete = _fileRepFactory.ChunkComplete(internalFileId); if (chunkComplete.Exist()) { chunkStart.Delete(); chunkComplete.Delete(); } if (!chunkStart.Exist()) { chunkStart.Write(fileLength.ToString()); } int bytesRead; do { if (cancellationToken.IsCancellationRequested) { break; } var buffer = new byte[ByteChunkSize]; bytesRead = await stream.ReadAsync(buffer, 0, ByteChunkSize, cancellationToken); fileLength += bytesRead; if (fileLength > uploadLength) { throw new TusStoreException( $"Stream contains more data than the file's upload length. Stream data: {fileLength}, upload length: {uploadLength}."); } file.Write(buffer, 0, bytesRead); bytesWritten += bytesRead; } while (bytesRead != 0); // Chunk is complete. Mark it as complete. chunkComplete.Write("1"); return(bytesWritten); } }
/// <inheritdoc /> public async Task <long> AppendDataAsync(string fileId, Stream stream, CancellationToken cancellationToken) { var internalFileId = await InternalFileId.Parse(_fileIdProvider, fileId); var httpReadBuffer = _bufferPool.Rent(_maxReadBufferSize); var fileWriteBuffer = _bufferPool.Rent(Math.Max(_maxWriteBufferSize, _maxReadBufferSize)); try { var fileUploadLengthProvidedDuringCreate = await GetUploadLengthAsync(fileId, cancellationToken); using var diskFileStream = _fileRepFactory.Data(internalFileId).GetStream(FileMode.Append, FileAccess.Write, FileShare.None); var totalDiskFileLength = diskFileStream.Length; if (fileUploadLengthProvidedDuringCreate == totalDiskFileLength) { return(0); } var chunkCompleteFile = InitializeChunk(internalFileId, totalDiskFileLength); int numberOfbytesReadFromClient; var bytesWrittenThisRequest = 0L; var clientDisconnectedDuringRead = false; var writeBufferNextFreeIndex = 0; do { if (cancellationToken.IsCancellationRequested) { break; } numberOfbytesReadFromClient = await stream.ReadAsync(httpReadBuffer, 0, _maxReadBufferSize, cancellationToken); clientDisconnectedDuringRead = cancellationToken.IsCancellationRequested; totalDiskFileLength += numberOfbytesReadFromClient; if (totalDiskFileLength > fileUploadLengthProvidedDuringCreate) { throw new TusStoreException($"Stream contains more data than the file's upload length. Stream data: {totalDiskFileLength}, upload length: {fileUploadLengthProvidedDuringCreate}."); } // Can we fit the read data into the write buffer? If not flush it now. if (writeBufferNextFreeIndex + numberOfbytesReadFromClient > _maxWriteBufferSize) { await FlushFileToDisk(fileWriteBuffer, diskFileStream, writeBufferNextFreeIndex); writeBufferNextFreeIndex = 0; } Array.Copy( sourceArray: httpReadBuffer, sourceIndex: 0, destinationArray: fileWriteBuffer, destinationIndex: writeBufferNextFreeIndex, length: numberOfbytesReadFromClient); writeBufferNextFreeIndex += numberOfbytesReadFromClient; bytesWrittenThisRequest += numberOfbytesReadFromClient; } while (numberOfbytesReadFromClient != 0); // Flush the remaining buffer to disk. if (writeBufferNextFreeIndex != 0) { await FlushFileToDisk(fileWriteBuffer, diskFileStream, writeBufferNextFreeIndex); } if (!clientDisconnectedDuringRead) { MarkChunkComplete(chunkCompleteFile); } return(bytesWrittenThisRequest); } finally { _bufferPool.Return(httpReadBuffer); _bufferPool.Return(fileWriteBuffer); } }
/// <inheritdoc /> public async Task <long> AppendDataAsync(string fileId, Stream stream, CancellationToken cancellationToken) { var internalFileId = new InternalFileId(fileId); var reciveReadBuffer = new byte[_maxReadBufferSize]; long bytesWritten = 0; var uploadLength = await GetUploadLengthAsync(fileId, cancellationToken); using (var writeBuffer = new MemoryStream(_maxWriteBufferSize)) using (var file = _fileRepFactory.Data(internalFileId).GetStream(FileMode.Append, FileAccess.Write, FileShare.None)) { var fileLength = file.Length; if (uploadLength == fileLength) { return(0); } var chunkStart = _fileRepFactory.ChunkStartPosition(internalFileId); var chunkComplete = _fileRepFactory.ChunkComplete(internalFileId); if (chunkComplete.Exist()) { chunkStart.Delete(); chunkComplete.Delete(); } if (!chunkStart.Exist()) { chunkStart.Write(fileLength.ToString()); } int bytesRead; do { if (cancellationToken.IsCancellationRequested) { break; } bytesRead = await stream.ReadAsync(reciveReadBuffer, 0, _maxReadBufferSize, cancellationToken); fileLength += bytesRead; if (fileLength > uploadLength) { throw new TusStoreException( $"Stream contains more data than the file's upload length. Stream data: {fileLength}, upload length: {uploadLength}."); } writeBuffer.Write(reciveReadBuffer, 0, bytesRead); bytesWritten += bytesRead; // If the buffer is above max size we flush it now. if (writeBuffer.Length >= _maxWriteBufferSize) { await FlushFileWriteBuffer(writeBuffer, file); } } while (bytesRead != 0); // Flush the remaining buffer to disk. if (writeBuffer.Length != 0) { await FlushFileWriteBuffer(writeBuffer, file); } if (!cancellationToken.IsCancellationRequested) { // Chunk is complete. Mark it as complete. chunkComplete.Write("1"); } return(bytesWritten); } }