using System;
using System.IO;
using System.Text;
using Best.HTTP.Shared.PlatformSupport.Memory;
using Best.HTTP.Shared.Streams;
namespace Best.HTTP.Request.Upload
{
///
/// An implementation to convert and upload the object as JSON data. It sets the "Content-Type" header to "application/json; charset=utf-8".
///
/// The type of the object to be converted to JSON.
///
/// This stream keeps a reference to the object until the preparation in . This means, changes to the object after passing it to the constructor will be reflected in the sent data too.
/// The return value of is treated specially in the plugin:
///
/// -
/// Less than zero(-1) value
/// indicates that no data is currently available but more is expected in the future. In this case, when new data becomes available the IThreadSignaler object must be signaled.
///
/// -
/// Zero (0)
/// means that the stream is closed, no more data can be expected.
///
///
/// A zero value to signal stream closure can follow a less than zero value.
///
public sealed class JSonDataStream : UploadStreamBase
{
public override long Length { get => this._innerStream.Length; }
private BufferPoolMemoryStream _innerStream;
private T _objToJson;
///
/// Initializes a new instance of the class with the specified object.
///
/// The object to be converted to JSON and uploaded.
public JSonDataStream(T obj) => this._objToJson = obj;
///
/// Called before sending out the request's headers. It sets the "Content-Type" header to "application/json; charset=utf-8".
///
/// The HTTP request.
public override void BeforeSendHeaders(HTTPRequest request)
{
request.SetHeader("Content-Type", "application/json; charset=utf-8");
if (this._innerStream != null)
{
this._innerStream.Position = 0;
return;
}
var json = Best.HTTP.JSON.LitJson.JsonMapper.ToJson(this._objToJson);
this._objToJson = default;
var byteLength = Encoding.UTF8.GetByteCount(json);
var buffer = BufferPool.Get(byteLength, true);
Encoding.UTF8.GetBytes(json, 0, json.Length, buffer, 0);
this._innerStream = new BufferPoolMemoryStream(byteLength);
this._innerStream.Write(buffer, 0, byteLength);
this._innerStream.Position = 0;
BufferPool.Release(buffer);
}
///
/// Reads a sequence of bytes from the current stream and advances the position within the stream by the number of bytes read.
///
/// An array of bytes. When this method returns, the buffer contains the specified byte array with the values between and ( + - 1) replaced by the bytes read from the current source.
/// The zero-based byte offset in at which to begin storing the data read from the current stream.
/// The maximum number of bytes to be read from the current stream.
/// The total number of bytes read into the buffer. This can be less than the number of bytes requested if that many bytes are not currently available, or zero (0) if the end of the stream has been reached.
public override int Read(byte[] buffer, int offset, int count) => this._innerStream.Read(buffer, offset, count);
///
/// Releases the unmanaged resources used by the and optionally releases the managed resources.
///
/// true to release both managed and unmanaged resources; false to release only unmanaged resources.
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
this._objToJson = default;
this._innerStream?.Dispose();
this._innerStream = null;
}
public override bool CanRead => true;
public override bool CanSeek => false;
public override bool CanWrite => false;
public override long Position { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public override void Flush() { }
public override long Seek(long offset, SeekOrigin origin) => throw new NotImplementedException();
public override void SetLength(long value) { throw new NotImplementedException(); }
public override void Write(byte[] buffer, int offset, int count) { throw new NotImplementedException(); }
}
}