namespace KianaBH.KcpSharp.Base; /// /// A stream wrapper of . /// public sealed class KcpStream : Stream { private readonly bool _ownsConversation; private KcpConversation? _conversation; /// /// Create a stream wrapper over an existing instance. /// /// The conversation instance. It must be in stream mode. /// /// Whether to dispose the instance when /// is disposed. /// public KcpStream(KcpConversation conversation, bool ownsConversation) { if (conversation is null) throw new ArgumentNullException(nameof(conversation)); if (!conversation.StreamMode) throw new ArgumentException("Non-stream mode conversation is not supported.", nameof(conversation)); _conversation = conversation; _ownsConversation = ownsConversation; } /// public override bool CanRead => true; /// public override bool CanSeek => false; /// public override bool CanWrite => true; /// /// The length of the stream. This always throws . /// public override long Length => throw new NotSupportedException(); /// /// The position of the stream. This always throws . /// public override long Position { get => throw new NotSupportedException(); set => throw new NotSupportedException(); } /// /// Indicates data is available on the stream to be read. This property checks to see if at least one byte of data is /// currently available /// public bool DataAvailable { get { if (_conversation is null) ThrowHelper.ThrowObjectDisposedForKcpStreamException(); return _conversation!.TryPeek(out var result) && result.BytesReceived != 0; } } /// public override long Seek(long offset, SeekOrigin origin) { throw new NotSupportedException(); } /// public override void SetLength(long value) { throw new NotSupportedException(); } /// public override void Flush() { throw new NotSupportedException(); } /// public override Task FlushAsync(CancellationToken cancellationToken) { if (_conversation is null) return Task.FromException(ThrowHelper.NewObjectDisposedForKcpStreamException()); return _conversation!.FlushAsync(cancellationToken).AsTask(); } /// public override int Read(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } /// public override void Write(byte[] buffer, int offset, int count) { throw new NotSupportedException(); } /// public override Task ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (_conversation is null) return Task.FromException(new ObjectDisposedException(nameof(KcpStream))); return _conversation.ReadAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); } /// public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken) { if (_conversation is null) return Task.FromException(new ObjectDisposedException(nameof(KcpStream))); return _conversation.WriteAsync(buffer.AsMemory(offset, count), cancellationToken).AsTask(); } /// public override int ReadByte() { throw new NotSupportedException(); } /// public override void WriteByte(byte value) { throw new NotSupportedException(); } /// protected override void Dispose(bool disposing) { if (disposing && _ownsConversation) _conversation?.Dispose(); _conversation = null; base.Dispose(disposing); } #if !NO_FAST_SPAN /// public override ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) { if (_conversation is null) return new ValueTask(Task.FromException(new ObjectDisposedException(nameof(KcpStream)))); return _conversation.ReadAsync(buffer, cancellationToken); } /// public override ValueTask WriteAsync(ReadOnlyMemory buffer, CancellationToken cancellationToken = default) { if (_conversation is null) return new ValueTask(Task.FromException(new ObjectDisposedException(nameof(KcpStream)))); return _conversation.WriteAsync(buffer, cancellationToken); } /// public override ValueTask DisposeAsync() { if (_conversation is not null) { _conversation.Dispose(); _conversation = null; } return base.DisposeAsync(); } /// public override int Read(Span buffer) { throw new NotSupportedException(); } /// public override void Write(ReadOnlySpan buffer) { throw new NotSupportedException(); } #endif }