You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
222 lines
5.9 KiB
222 lines
5.9 KiB
8 months ago
|
using BestHTTP;
|
||
|
using System;
|
||
|
using System.IO;
|
||
|
using System.Threading;
|
||
|
|
||
|
namespace BestHTTP.Examples
|
||
|
{
|
||
|
public sealed class UploadStream : Stream
|
||
|
{
|
||
|
#region Private Fields
|
||
|
|
||
|
/// <summary>
|
||
|
/// Buffer for reads
|
||
|
/// </summary>
|
||
|
MemoryStream ReadBuffer = new MemoryStream();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Buffer for writes
|
||
|
/// </summary>
|
||
|
MemoryStream WriteBuffer = new MemoryStream();
|
||
|
|
||
|
/// <summary>
|
||
|
/// Indicates that we will not write more data to this stream
|
||
|
/// </summary>
|
||
|
bool noMoreData;
|
||
|
|
||
|
/// <summary>
|
||
|
/// For thread synchronization
|
||
|
/// </summary>
|
||
|
AutoResetEvent ARE = new AutoResetEvent(false);
|
||
|
|
||
|
/// <summary>
|
||
|
/// For thread synchronization
|
||
|
/// </summary>
|
||
|
object locker = new object();
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Properties
|
||
|
|
||
|
/// <summary>
|
||
|
/// Name of this stream for easier debugging
|
||
|
/// </summary>
|
||
|
public string Name { get; private set; }
|
||
|
|
||
|
/// <summary>
|
||
|
/// true if we are read all data from the read buffer
|
||
|
/// </summary>
|
||
|
private bool IsReadBufferEmpty { get { lock (locker) return ReadBuffer.Position == ReadBuffer.Length; } }
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Constructors
|
||
|
|
||
|
public UploadStream(string name)
|
||
|
: this()
|
||
|
{
|
||
|
this.Name = name;
|
||
|
}
|
||
|
|
||
|
public UploadStream()
|
||
|
{
|
||
|
this.ReadBuffer = new MemoryStream();
|
||
|
this.WriteBuffer = new MemoryStream();
|
||
|
this.Name = string.Empty;
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Stream Implementation
|
||
|
|
||
|
public override int Read(byte[] buffer, int offset, int count)
|
||
|
{
|
||
|
// We will not push more data to the write buffer
|
||
|
if (noMoreData)
|
||
|
{
|
||
|
// No data left in the read buffer
|
||
|
if (ReadBuffer.Position == ReadBuffer.Length)
|
||
|
{
|
||
|
// Is there any data in the write buffer? If so, switch the buffers
|
||
|
if (WriteBuffer.Length > 0)
|
||
|
SwitchBuffers();
|
||
|
else
|
||
|
{
|
||
|
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Read - End Of Stream", this.Name));
|
||
|
return -1;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
return ReadBuffer.Read(buffer, offset, count);
|
||
|
}
|
||
|
|
||
|
// There are no more data in the read buffer? Wait for it.
|
||
|
if (IsReadBufferEmpty)
|
||
|
{
|
||
|
ARE.WaitOne();
|
||
|
|
||
|
lock (locker)
|
||
|
if (IsReadBufferEmpty && WriteBuffer.Length > 0)
|
||
|
SwitchBuffers();
|
||
|
}
|
||
|
|
||
|
int read = -1;
|
||
|
|
||
|
lock (locker)
|
||
|
read = ReadBuffer.Read(buffer, offset, count);
|
||
|
|
||
|
return read;
|
||
|
}
|
||
|
|
||
|
public override void Write(byte[] buffer, int offset, int count)
|
||
|
{
|
||
|
if (noMoreData)
|
||
|
throw new System.ArgumentException("noMoreData already set!");
|
||
|
|
||
|
lock (locker)
|
||
|
{
|
||
|
WriteBuffer.Write(buffer, offset, count);
|
||
|
|
||
|
SwitchBuffers();
|
||
|
}
|
||
|
|
||
|
ARE.Set();
|
||
|
}
|
||
|
|
||
|
public override void Flush()
|
||
|
{
|
||
|
Finish();
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Dispose Implementation
|
||
|
|
||
|
protected override void Dispose(bool disposing)
|
||
|
{
|
||
|
if (disposing)
|
||
|
{
|
||
|
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Dispose", this.Name));
|
||
|
|
||
|
ReadBuffer.Dispose();
|
||
|
ReadBuffer = null;
|
||
|
|
||
|
WriteBuffer.Dispose();
|
||
|
WriteBuffer = null;
|
||
|
|
||
|
#if NETFX_CORE
|
||
|
ARE.Dispose();
|
||
|
#else
|
||
|
ARE.Close();
|
||
|
#endif
|
||
|
ARE = null;
|
||
|
}
|
||
|
|
||
|
base.Dispose(disposing);
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Helper Functions
|
||
|
|
||
|
public void Finish()
|
||
|
{
|
||
|
if (noMoreData)
|
||
|
throw new System.ArgumentException("noMoreData already set!");
|
||
|
|
||
|
HTTPManager.Logger.Information("UploadStream", string.Format("{0} - Finish", this.Name));
|
||
|
|
||
|
noMoreData = true;
|
||
|
|
||
|
ARE.Set();
|
||
|
}
|
||
|
|
||
|
private bool SwitchBuffers()
|
||
|
{
|
||
|
// Switch the buffers only when all data are consumed from our read buffer
|
||
|
lock (locker)
|
||
|
{
|
||
|
if (ReadBuffer.Position == ReadBuffer.Length)
|
||
|
{
|
||
|
// This buffer will be the read buffer, we need to seek back to the beginning
|
||
|
WriteBuffer.Seek(0, SeekOrigin.Begin);
|
||
|
|
||
|
// This will be the write buffer, set the length to zero
|
||
|
ReadBuffer.SetLength(0);
|
||
|
|
||
|
// switch the two buffers
|
||
|
MemoryStream tmp = WriteBuffer;
|
||
|
WriteBuffer = ReadBuffer;
|
||
|
ReadBuffer = tmp;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
|
||
|
#region Not Implemented Functions and Properties
|
||
|
|
||
|
public override bool CanRead { get { throw new NotImplementedException(); } }
|
||
|
public override bool CanSeek { get { throw new NotImplementedException(); } }
|
||
|
public override bool CanWrite { get { throw new NotImplementedException(); } }
|
||
|
|
||
|
public override long Length { get { throw new NotImplementedException(); } }
|
||
|
public override long Position { get { throw new NotImplementedException(); } set { throw new NotImplementedException(); } }
|
||
|
|
||
|
public override long Seek(long offset, SeekOrigin origin)
|
||
|
{
|
||
|
throw new NotImplementedException();
|
||
|
}
|
||
|
|
||
|
public override void SetLength(long value)
|
||
|
{
|
||
|
throw new NotImplementedException();
|
||
|
}
|
||
|
|
||
|
#endregion
|
||
|
}
|
||
|
}
|