Пример #1
0
        /// <summary>
        ///   Performs the chunking.
        /// </summary>
        /// <param name="stream">
        ///   The data source.
        /// </param>
        /// <param name="name">
        ///   A name for the data.
        /// </param>
        /// <param name="options">
        ///   The options when adding data to the IPFS file system.
        /// </param>
        /// <param name="blockService">
        ///   The destination for the chunked data block(s).
        /// </param>
        /// <param name="keyChain">
        ///   Used to protect the chunked data blocks(s).
        /// </param>
        /// <param name="cancel">
        ///   Is used to stop the task.  When cancelled, the <see cref="TaskCanceledException"/> is raised.
        /// </param>
        /// <returns>
        ///    A task that represents the asynchronous operation. The task's value is
        ///    the sequence of file system nodes of the added data blocks.
        /// </returns>
        public async Task <IEnumerable <FileSystemNode> > ChunkAsync(
            Stream stream,
            string name,
            AddFileOptions options,
            IBlockApi blockService,
            KeyChain keyChain,
            CancellationToken cancel)
        {
            var protecting = !string.IsNullOrWhiteSpace(options.ProtectionKey);
            var nodes      = new List <FileSystemNode> ();
            var chunkSize  = options.ChunkSize;
            var chunk      = new byte[chunkSize];
            var chunking   = true;
            var totalBytes = 0UL;

            while (chunking)
            {
                // Get an entire chunk.
                int length = 0;
                while (length < chunkSize)
                {
                    var n = await stream.ReadAsync(chunk, length, chunkSize - length, cancel);

                    if (n < 1)
                    {
                        chunking = false;
                        break;
                    }
                    length     += n;
                    totalBytes += (uint)n;
                }

                //  Only generate empty block, when the stream is empty.
                if (length == 0 && nodes.Count > 0)
                {
                    chunking = false;
                    break;
                }

                if (options.Progress != null)
                {
                    options.Progress.Report(new TransferProgress
                    {
                        Name  = name,
                        Bytes = totalBytes
                    });
                }
                // if protected data, then get CMS structure.
                if (protecting)
                {
                    // TODO: Inefficent to copy chunk, use ArraySegment in DataMessage.Data
                    var plain = new byte[length];
                    Array.Copy(chunk, plain, length);
                    var cipher = await keyChain.CreateProtectedData(options.ProtectionKey, plain, cancel);

                    var cid = await blockService.PutAsync(
                        data : cipher,
                        contentType : "cms",
                        multiHash : options.Hash,
                        encoding : options.Encoding,
                        pin : options.Pin,
                        cancel : cancel);

                    nodes.Add(new FileSystemNode
                    {
                        Id      = cid,
                        Size    = length,
                        DagSize = cipher.Length,
                        Links   = FileSystemLink.None
                    });
                }
                else if (options.RawLeaves)
                {
                    // TODO: Inefficent to copy chunk, use ArraySegment in DataMessage.Data
                    var data = new byte[length];
                    Array.Copy(chunk, data, length);
                    var cid = await blockService.PutAsync(
                        data : data,
                        contentType : "raw",
                        multiHash : options.Hash,
                        encoding : options.Encoding,
                        pin : options.Pin,
                        cancel : cancel);

                    nodes.Add(new FileSystemNode
                    {
                        Id      = cid,
                        Size    = length,
                        DagSize = length,
                        Links   = FileSystemLink.None
                    });
                }
                else
                {
                    // Build the DAG.
                    var dm = new DataMessage
                    {
                        Type     = DataType.File,
                        FileSize = (ulong)length,
                    };
                    if (length > 0)
                    {
                        // TODO: Inefficent to copy chunk, use ArraySegment in DataMessage.Data
                        var data = new byte[length];
                        Array.Copy(chunk, data, length);
                        dm.Data = data;
                    }
                    var pb = new MemoryStream();
                    ProtoBuf.Serializer.Serialize <DataMessage>(pb, dm);
                    var dag = new DagNode(pb.ToArray(), null, options.Hash);

                    // Save it.
                    dag.Id = await blockService.PutAsync(
                        data : dag.ToArray(),
                        multiHash : options.Hash,
                        encoding : options.Encoding,
                        pin : options.Pin,
                        cancel : cancel);

                    var node = new FileSystemNode
                    {
                        Id      = dag.Id,
                        Size    = length,
                        DagSize = dag.Size,
                        Links   = FileSystemLink.None
                    };
                    nodes.Add(node);
                }
            }

            return(nodes);
        }