WriteOnlyBufferedStream.cs 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. using System;
  2. using System.IO;
  3. using Best.HTTP.Shared.Extensions;
  4. using Best.HTTP.Shared.Logger;
  5. using Best.HTTP.Shared.PlatformSupport.Memory;
  6. namespace Best.HTTP.Shared.Streams
  7. {
  8. /// <summary>
  9. /// A custom buffer stream implementation that will not close the underlying stream.
  10. /// </summary>
  11. public sealed class WriteOnlyBufferedStream : Stream
  12. {
  13. public override bool CanRead { get { return false; } }
  14. public override bool CanSeek { get { return false; } }
  15. public override bool CanWrite { get { return true; } }
  16. public override long Length { get { return this.buffer.Length; } }
  17. public override long Position { get { return this._position; } set { throw new NotImplementedException("Position set"); } }
  18. private int _position;
  19. private byte[] buffer;
  20. private int _bufferSize;
  21. private Stream stream;
  22. private LoggingContext _context;
  23. public WriteOnlyBufferedStream(Stream stream, int bufferSize, LoggingContext context)
  24. {
  25. if (stream == null)
  26. throw new NullReferenceException(nameof(stream));
  27. this.stream = stream;
  28. this._context = context;
  29. this._bufferSize = bufferSize;
  30. this.buffer = BufferPool.Get(this._bufferSize, true, context);
  31. this._position = 0;
  32. }
  33. public override void Flush()
  34. {
  35. if (this._position > 0)
  36. {
  37. #if !UNITY_WEBGL || UNITY_EDITOR
  38. // if the underlying stream is an ITCPStreamerContentConsumer, we can use an optimized path and avoid copying
  39. // the buffered bytes.
  40. var tcpStreamer = this.stream as Shared.PlatformSupport.Network.Tcp.ITCPStreamerContentConsumer;
  41. if (tcpStreamer != null)
  42. {
  43. // First swap the buffers because tcpStreamer.Write might cause an exception and both the streamer
  44. // and WriteOnlyBufferedStream would release the same buffer
  45. var buff = this.buffer.AsBuffer(this._position);
  46. this.buffer = BufferPool.Get(this._bufferSize, true, this._context);
  47. tcpStreamer.Write(buff);
  48. }
  49. else
  50. #endif
  51. {
  52. this.stream.Write(this.buffer, 0, this._position);
  53. this.stream.Flush();
  54. }
  55. //if (HTTPManager.Logger.IsDiagnostic)
  56. // HTTPManager.Logger.Information("WriteOnlyBufferedStream", string.Format("Flushed {0:N0} bytes", this._position));
  57. this._position = 0;
  58. }
  59. }
  60. public override void Write(byte[] bufferFrom, int offset, int count)
  61. {
  62. while (count > 0)
  63. {
  64. int writeCount = Math.Min(count, this.buffer.Length - this._position);
  65. Array.Copy(bufferFrom, offset, this.buffer, this._position, writeCount);
  66. this._position += writeCount;
  67. offset += writeCount;
  68. count -= writeCount;
  69. if (this._position == this.buffer.Length)
  70. this.Flush();
  71. }
  72. }
  73. public override int Read(byte[] buffer, int offset, int count)
  74. {
  75. return 0;
  76. }
  77. public override long Seek(long offset, SeekOrigin origin)
  78. {
  79. return 0;
  80. }
  81. public override void SetLength(long value) { }
  82. protected override void Dispose(bool disposing)
  83. {
  84. base.Dispose(disposing);
  85. if (disposing && this.buffer != null)
  86. BufferPool.Release(this.buffer);
  87. this.buffer = null;
  88. }
  89. }
  90. }