/// <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);
            }
        }
Exemple #2
0
        /// <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);
            }
        }
Exemple #3
0
        /// <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);
                }
        }