UploadStream.cs 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. using BestHTTP;
  2. using System;
  3. using System.IO;
  4. using System.Threading;
  5. namespace BestHTTP.Examples
  6. {
  7. public sealed class UploadStream : Stream
  8. {
  9. #region Private Fields
  10. /// <summary>
  11. /// Buffer for reads
  12. /// </summary>
  13. MemoryStream ReadBuffer = new MemoryStream();
  14. /// <summary>
  15. /// Buffer for writes
  16. /// </summary>
  17. MemoryStream WriteBuffer = new MemoryStream();
  18. /// <summary>
  19. /// Indicates that we will not write more data to this stream
  20. /// </summary>
  21. bool noMoreData;
  22. /// <summary>
  23. /// For thread synchronization
  24. /// </summary>
  25. AutoResetEvent ARE = new AutoResetEvent(false);
  26. /// <summary>
  27. /// For thread synchronization
  28. /// </summary>
  29. object locker = new object();
  30. #endregion
  31. #region Properties
  32. /// <summary>
  33. /// Name of this stream for easier debugging
  34. /// </summary>
  35. public string Name { get; private set; }
  36. /// <summary>
  37. /// true if we are read all data from the read buffer
  38. /// </summary>
  39. private bool IsReadBufferEmpty { get { lock (locker) return ReadBuffer.Position == ReadBuffer.Length; } }
  40. #endregion
  41. #region Constructors
  42. public UploadStream(string name)
  43. : this()
  44. {
  45. this.Name = name;
  46. }
  47. public UploadStream()
  48. {
  49. this.ReadBuffer = new MemoryStream();
  50. this.WriteBuffer = new MemoryStream();
  51. this.Name = string.Empty;
  52. }
  53. #endregion
  54. #region Stream Implementation
  55. public override int Read(byte[] buffer, int offset, int count)
  56. {
  57. // We will not push more data to the write buffer
  58. if (noMoreData)
  59. {
  60. // No data left in the read buffer
  61. if (ReadBuffer.Position == ReadBuffer.Length)
  62. {
  63. // Is there any data in the write buffer? If so, switch the buffers
  64. if (WriteBuffer.Length > 0)
  65. SwitchBuffers();
  66. else
  67. {
  68. HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Read - End Of Stream", this.Name));
  69. return -1;
  70. }
  71. }
  72. else
  73. return ReadBuffer.Read(buffer, offset, count);
  74. }
  75. // There are no more data in the read buffer? Wait for it.
  76. if (IsReadBufferEmpty)
  77. {
  78. ARE.WaitOne();
  79. lock (locker)
  80. if (IsReadBufferEmpty && WriteBuffer.Length > 0)
  81. SwitchBuffers();
  82. }
  83. int read = -1;
  84. lock (locker)
  85. read = ReadBuffer.Read(buffer, offset, count);
  86. return read;
  87. }
  88. public override void Write(byte[] buffer, int offset, int count)
  89. {
  90. if (noMoreData)
  91. throw new System.ArgumentException("noMoreData already set!");
  92. lock (locker)
  93. {
  94. WriteBuffer.Write(buffer, offset, count);
  95. SwitchBuffers();
  96. }
  97. ARE.Set();
  98. }
  99. public override void Flush()
  100. {
  101. Finish();
  102. }
  103. #endregion
  104. #region Dispose Implementation
  105. protected override void Dispose(bool disposing)
  106. {
  107. if (disposing)
  108. {
  109. HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Dispose", this.Name));
  110. ReadBuffer.Dispose();
  111. ReadBuffer = null;
  112. WriteBuffer.Dispose();
  113. WriteBuffer = null;
  114. #if NETFX_CORE
  115. ARE.Dispose();
  116. #else
  117. ARE.Close();
  118. #endif
  119. ARE = null;
  120. }
  121. base.Dispose(disposing);
  122. }
  123. #endregion
  124. #region Helper Functions
  125. public void Finish()
  126. {
  127. if (noMoreData)
  128. throw new System.ArgumentException("noMoreData already set!");
  129. HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Finish", this.Name));
  130. noMoreData = true;
  131. ARE.Set();
  132. }
  133. private bool SwitchBuffers()
  134. {
  135. // Switch the buffers only when all data are consumed from our read buffer
  136. lock (locker)
  137. {
  138. if (ReadBuffer.Position == ReadBuffer.Length)
  139. {
  140. // This buffer will be the read buffer, we need to seek back to the beginning
  141. WriteBuffer.Seek(0, SeekOrigin.Begin);
  142. // This will be the write buffer, set the length to zero
  143. ReadBuffer.SetLength(0);
  144. // switch the two buffers
  145. MemoryStream tmp = WriteBuffer;
  146. WriteBuffer = ReadBuffer;
  147. ReadBuffer = tmp;
  148. return true;
  149. }
  150. }
  151. return false;
  152. }
  153. #endregion
  154. #region Not Implemented Functions and Properties
  155. public override bool CanRead { get { throw new NotImplementedException(); } }
  156. public override bool CanSeek { get { throw new NotImplementedException(); } }
  157. public override bool CanWrite { get { throw new NotImplementedException(); } }
  158. public override long Length { get { throw new NotImplementedException(); } }
  159. public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
  160. public override long Seek(long offset, SeekOrigin origin)
  161. {
  162. throw new NotImplementedException();
  163. }
  164. public override void SetLength(long value)
  165. {
  166. throw new NotImplementedException();
  167. }
  168. #endregion
  169. }
  170. }