/// <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); } }
public void Init() { receivedBlocks = new List<BufferedDataBlock>(); source = new byte[100000]; target = new List<byte>(); new Random(DateTime.Now.Millisecond).NextBytes(source); token = new UploadToken { TransferId = "MyToken", MaxBlockSize = 3000 }; }
public void Init() { receivedBlocks = new List<BufferedDataBlock>(); source = new byte[100000]; target = new List<byte>(); new Random(DateTime.Now.Millisecond).NextBytes(source); //token indicates 10 blocks were already submitted token = new UploadToken { TransferId = "MyToken", MaxBlockSize = 3000, TransmittedBlockCount = 10}; }
/// <summary> /// Initializes a new instance of the <see cref="T:System.IO.Stream"/> class. /// </summary> /// <param name="autoFlushThreshold">A threshold that causes the stream to aumatically flush /// its internal buffer once it reaches the defined size.<br/> /// If the threshold is 0, every write is immediately flushed.</param> /// <param name="outputAction">An action that is being invoked with created /// <see cref="BufferedDataBlock"/> instances when flushing the internal buffer.</param> /// <exception cref="ArgumentNullException">If <paramref name="token"/> or <paramref name="outputAction" /// is a null reference.</exception> /// <exception cref="ArgumentOutOfRangeException">Inf case the <paramref name="autoFlushThreshold"/> /// is negative.</exception> public BufferedBlockOutputStream(UploadToken token, int autoFlushThreshold, Action<BufferedDataBlock> outputAction) { if (token == null) throw new ArgumentNullException("token"); if (outputAction == null) throw new ArgumentNullException("outputAction"); if(autoFlushThreshold < 0) { throw new ArgumentOutOfRangeException("autoFlushThreshold", "Threshold for automatic flushing cannot be negative"); } Token = token; AutoFlushThreshold = autoFlushThreshold; OutputAction = outputAction; InitialOffset = token.NextBlockOffset; }
/// <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); } }
/// <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 writes the whole stream to the target. In order to resume a transfer and start in the /// middle of the stream, use the overload of this method that takes an initial block number and 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. It is assumed that /// the reading position within the stream has already been set.</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="writerAction">An action that is being invoked for every created <see cref="StreamedDataBlock"/> /// instance.</param> public static void WriteTo(this Stream sourceStream, UploadToken token, long resourceLength, int blockSize, Action<StreamedDataBlock> writerAction) { WriteTo(sourceStream, token, resourceLength, blockSize, 0, 0, writerAction); }
/// <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 writes the whole stream to the target. In order to resume a transfer and start in the /// middle of the stream, use the overload of this method that takes an initial block number and 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. It is assumed that /// the reading position within the stream has already been set.</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="writerAction">An action that is being invoked for every created <see cref="StreamedDataBlock"/> /// instance.</param> public static void WriteTo(this Stream sourceStream, UploadToken token, long resourceLength, int blockSize, Action <StreamedDataBlock> writerAction) { WriteTo(sourceStream, token, resourceLength, blockSize, 0, 0, writerAction); }
/// <summary> /// Gets a download token for the <see cref="TargetFile"/> and /// assigns it to the <see cref="Token"/> property. /// </summary> /// <returns>The retrieved token.</returns> protected UploadToken InitToken() { Token = Uploads.RequestUploadToken(TargetFilePath, false, SourceFile.Length, "binary"); return Token; }