コード例 #1
0
        /// <summary>
        /// Splits a stream into chunks using a <see cref="ChunkStream"/>, and wraps them into
        /// <see cref="StreamedDataBlock"/> instances that can be sent to an <see cref="IUploadTransferHandler"/>.
        /// This overload allows to resume a transfer and start with a given offset.
        /// <br/>This extension method also takes care of implicitly completing the upload by setting the
        /// <see cref="IDataBlock.IsLastBlock"/> property of the last block to true.
        /// </summary>
        /// <param name="sourceStream">The source stream that provides the data to be uploaded.</param>
        /// <param name="token">An upload token that defines the resource.</param>
        /// <param name="resourceLength">The total length of the submitted stream.</param>
        /// <param name="blockSize">The block size to be used. All blocks (except the last one) will have
        /// this size.</param>
        /// <param name="initialBlockNumber">The initial block number to be used.</param>
        /// <param name="offset">The offset of the first written block (0 to start at the beginning of the stream).</param>
        /// <param name="writerAction">An action that is being invoked for every created <see cref="StreamedDataBlock"/>
        /// instance.</param>
        /// <remarks>The position within the stream is only set according to the submitted
        /// <paramref name="offset"/> if the underlying <paramref name="sourceStream"/> supports seeking as indicated by
        /// its <see cref="Stream.CanSeek"/> property.</remarks>
        public static void WriteTo(this Stream sourceStream, UploadToken token, long resourceLength, int blockSize, long initialBlockNumber, long offset, Action <StreamedDataBlock> writerAction)
        {
            long remaining   = resourceLength;
            long position    = offset;
            long blockNumber = initialBlockNumber;

            while (remaining > 0)
            {
                //decorate the stream with a chunk stream that limits access to a block of data
                int         chunkSize = (int)Math.Min(remaining, blockSize);
                ChunkStream cs        = new ChunkStream(sourceStream, chunkSize, position, sourceStream.CanSeek);

                StreamedDataBlock dataBlock = new StreamedDataBlock
                {
                    TransferTokenId = token.TransferId,
                    BlockLength     = chunkSize,
                    BlockNumber     = blockNumber,
                    Data            = cs,
                    Offset          = position
                };

                //update position within stream and remaining bytes
                position  += chunkSize;
                remaining -= chunkSize;
                blockNumber++;

                if (remaining == 0)
                {
                    //implicitly complete the transfer by marking the last block
                    dataBlock.IsLastBlock = true;
                }

                writerAction(dataBlock);
            }
        }
コード例 #2
0
        /// <summary>
        /// Reads a block via a streaming channel, which enables a more resource friendly
        /// data transmission (compared to sending the whole data of the block at once).
        /// </summary>
        /// <param name="transferId"></param>
        /// <param name="blockNumber"></param>
        /// <returns></returns>
        public StreamedDataBlock ReadBlockStreamed(string transferId, long blockNumber)
        {
            //this func creates the returned DataBlock by reading a chunk of data
            //from the underlying stream.
            Func <DownloadTransfer, long, StreamedDataBlock> func = (dt, position) =>
            {
                DownloadToken token = dt.Token;

                //check if we can use the max block size
                long streamLength = dt.Stream.Length;
                long blockLength  = Math.Min(token.DownloadBlockSize.Value, streamLength - position);
                if (blockLength < 0)
                {
                    blockLength = 0;
                }

                ChunkStream stream = new ChunkStream(dt.Stream, blockLength, position, false);

                //if we're reading to the end of the stream, we're done
                bool isLastBlock = position + blockLength == streamLength;

                return(new StreamedDataBlock
                {
                    TransferTokenId = transferId,
                    BlockNumber = blockNumber,
                    BlockLength = blockLength,
                    Offset = position,
                    Data = stream,
                    IsLastBlock = isLastBlock
                });
            };

            return(PrepareBlockReading(transferId, blockNumber, func));
        }