internal Task SendAsync(long substreamId, byte[] data, CancellationToken cancellation)
 {
     return(SendAsync(linked => ProtobufEx.SerializeWithLengthPrefixAsync(Inner, new MultiplexPacket()
     {
         SubstreamId = substreamId == OutboundSubstream ? 0 : OutboundSubstream = substreamId,
         Data = data
     }, PrefixStyle.Base128, linked), cancellation));
 }
 internal void QueueClose(long substreamId)
 {
     lock (Substreams)
         Substreams.Remove(substreamId);
     SendAsync(async linked =>
     {
         await ProtobufEx.SerializeWithLengthPrefixAsync(Inner, new MultiplexPacket()
         {
             SubstreamId = substreamId == OutboundSubstream ? 0 : OutboundSubstream = substreamId,
             EndOfStream = true
         }, PrefixStyle.Base128, linked);
         await Inner.FlushAsync(linked);
     }, CancellationToken.None).ContinueWith(t => Logger.Error(t.Exception), TaskContinuationOptions.OnlyOnFaulted);
 }
        public async Task <Stream> ConnectAsync(CancellationToken cancellation)
        {
            MultiplexSubstream substream;

            lock (Substreams)
            {
                substream          = new MultiplexSubstream(this, NextId);
                Substreams[NextId] = substream;
                ++NextId;
            }
            await SendAsync(linked => ProtobufEx.SerializeWithLengthPrefixAsync(Inner, new MultiplexPacket()
            {
                SubstreamId = OutboundSubstream = substream.Id
            }, PrefixStyle.Base128, linked), cancellation);

            return(substream);
        }
        async void ReceiveAsync()
        {
            try
            {
                while (true)
                {
                    var packet = await ProtobufEx.DeserializeWithLengthPrefixAsync <MultiplexPacket>(Inner, PrefixStyle.Base128, CancelAll.Token);

                    if (packet.SubstreamId != 0)
                    {
                        InboundSubstream = -packet.SubstreamId;
                    }
                    else if (InboundSubstream == 0)
                    {
                        throw new FormatException();
                    }
                    MultiplexSubstream substream;
                    bool created = false;
                    lock (Substreams)
                    {
                        if (!Substreams.TryGetValue(InboundSubstream, out substream) && InboundSubstream < 0)
                        {
                            Substreams[InboundSubstream] = substream = new MultiplexSubstream(this, InboundSubstream);
                            created = true;
                        }
                    }
                    if (created)
                    {
                        await Pending.AddAsync(substream, CancelAll.Token);
                    }
                    if (substream != null)
                    {
                        if (packet.Data != null && packet.Data.Length > 0)
                        {
                            await substream.ReceiveAsync(packet.Data, CancelAll.Token);
                        }
                        if (packet.EndOfStream)
                        {
                            await substream.ReceiveEndOfStream(CancelAll.Token);
                        }
                    }
                }
            }
            catch (EndOfStreamException)
            {
                Dispose();
                List <MultiplexSubstream> substreams;
                lock (Substreams)
                    substreams = Substreams.Values.ToList();
                foreach (var substream in substreams)
                {
                    substream.Dispose();
                }
            }
            catch (Exception e)
            {
                if (!CancelAll.Token.IsCancellationRequested)
                {
                    Logger.Error(e);
                    Dispose();
                }
            }
        }