2018-09-27 10:50:39 -07:00
|
|
|
using System.IO;
|
|
|
|
|
using System.Net;
|
|
|
|
|
using System.Net.Http;
|
|
|
|
|
using System.Threading;
|
|
|
|
|
using System.Threading.Tasks;
|
|
|
|
|
|
|
|
|
|
namespace k8s
|
|
|
|
|
{
|
2022-03-09 03:40:00 +08:00
|
|
|
internal sealed class LineSeparatedHttpContent : HttpContent
|
2018-09-27 10:50:39 -07:00
|
|
|
{
|
2021-09-14 11:20:05 -07:00
|
|
|
private readonly HttpContent _originContent;
|
|
|
|
|
private readonly CancellationToken _cancellationToken;
|
|
|
|
|
private Stream _originStream;
|
|
|
|
|
|
|
|
|
|
public LineSeparatedHttpContent(HttpContent originContent, CancellationToken cancellationToken)
|
2018-09-27 10:50:39 -07:00
|
|
|
{
|
2021-09-14 11:20:05 -07:00
|
|
|
_originContent = originContent;
|
|
|
|
|
_cancellationToken = cancellationToken;
|
|
|
|
|
}
|
2018-09-27 10:50:39 -07:00
|
|
|
|
2021-09-14 11:20:05 -07:00
|
|
|
public TextReader StreamReader { get; private set; }
|
|
|
|
|
|
|
|
|
|
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext context)
|
|
|
|
|
{
|
|
|
|
|
_originStream = await _originContent.ReadAsStreamAsync().ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
var reader = new PeekableStreamReader(new CancelableStream(_originStream, _cancellationToken));
|
|
|
|
|
StreamReader = reader;
|
2020-03-22 21:18:45 -07:00
|
|
|
|
2021-09-14 11:20:05 -07:00
|
|
|
var firstLine = await reader.PeekLineAsync().ConfigureAwait(false);
|
|
|
|
|
|
|
|
|
|
var writer = new StreamWriter(stream);
|
|
|
|
|
|
|
|
|
|
await writer.WriteAsync(firstLine).ConfigureAwait(false);
|
|
|
|
|
await writer.FlushAsync().ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected override bool TryComputeLength(out long length)
|
|
|
|
|
{
|
|
|
|
|
length = 0;
|
|
|
|
|
return false;
|
2018-09-27 10:50:39 -07:00
|
|
|
}
|
|
|
|
|
|
2022-03-09 03:40:00 +08:00
|
|
|
internal sealed class CancelableStream : Stream
|
2020-03-22 21:18:45 -07:00
|
|
|
{
|
|
|
|
|
private readonly Stream _innerStream;
|
|
|
|
|
private readonly CancellationToken _cancellationToken;
|
|
|
|
|
|
|
|
|
|
public CancelableStream(Stream innerStream, CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
_innerStream = innerStream;
|
|
|
|
|
_cancellationToken = cancellationToken;
|
|
|
|
|
}
|
|
|
|
|
|
2020-04-01 03:45:27 +01:00
|
|
|
public override void Flush() =>
|
|
|
|
|
_innerStream.FlushAsync(_cancellationToken).GetAwaiter().GetResult();
|
|
|
|
|
|
|
|
|
|
public override async Task FlushAsync(CancellationToken cancellationToken)
|
|
|
|
|
{
|
|
|
|
|
using (var cancellationTokenSource = CreateCancellationTokenSource(cancellationToken))
|
|
|
|
|
{
|
|
|
|
|
await _innerStream.FlushAsync(cancellationTokenSource.Token).ConfigureAwait(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-22 21:18:45 -07:00
|
|
|
|
|
|
|
|
public override int Read(byte[] buffer, int offset, int count) =>
|
|
|
|
|
_innerStream.ReadAsync(buffer, offset, count, _cancellationToken).GetAwaiter().GetResult();
|
|
|
|
|
|
2020-04-23 11:40:06 -07:00
|
|
|
public override async Task<int> ReadAsync(byte[] buffer, int offset, int count,
|
|
|
|
|
CancellationToken cancellationToken)
|
2020-04-01 03:45:27 +01:00
|
|
|
{
|
|
|
|
|
using (var cancellationTokenSource = CreateCancellationTokenSource(cancellationToken))
|
|
|
|
|
{
|
2020-04-23 11:40:06 -07:00
|
|
|
return await _innerStream.ReadAsync(buffer, offset, count, cancellationTokenSource.Token)
|
|
|
|
|
.ConfigureAwait(false);
|
2020-04-01 03:45:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-22 21:18:45 -07:00
|
|
|
public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin);
|
|
|
|
|
|
|
|
|
|
public override void SetLength(long value) => _innerStream.SetLength(value);
|
|
|
|
|
|
|
|
|
|
public override void Write(byte[] buffer, int offset, int count) =>
|
|
|
|
|
_innerStream.WriteAsync(buffer, offset, count, _cancellationToken).GetAwaiter().GetResult();
|
|
|
|
|
|
2020-04-23 11:40:06 -07:00
|
|
|
public override async Task WriteAsync(byte[] buffer, int offset, int count,
|
|
|
|
|
CancellationToken cancellationToken)
|
2020-04-01 03:45:27 +01:00
|
|
|
{
|
|
|
|
|
using (var cancellationTokenSource = CreateCancellationTokenSource(cancellationToken))
|
|
|
|
|
{
|
2020-04-23 11:40:06 -07:00
|
|
|
await _innerStream.WriteAsync(buffer, offset, count, cancellationTokenSource.Token)
|
|
|
|
|
.ConfigureAwait(false);
|
2020-04-01 03:45:27 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-22 21:18:45 -07:00
|
|
|
public override bool CanRead => _innerStream.CanRead;
|
|
|
|
|
|
|
|
|
|
public override bool CanSeek => _innerStream.CanSeek;
|
|
|
|
|
|
|
|
|
|
public override bool CanWrite => _innerStream.CanWrite;
|
|
|
|
|
|
|
|
|
|
public override long Length => _innerStream.Length;
|
|
|
|
|
|
|
|
|
|
public override long Position
|
|
|
|
|
{
|
|
|
|
|
get => _innerStream.Position;
|
|
|
|
|
set => _innerStream.Position = value;
|
|
|
|
|
}
|
2020-04-01 03:45:27 +01:00
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
|
|
|
|
_innerStream.Dispose();
|
|
|
|
|
}
|
2020-04-23 11:40:06 -07:00
|
|
|
|
2020-04-01 03:45:27 +01:00
|
|
|
base.Dispose(disposing);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private LinkedCancellationTokenSource CreateCancellationTokenSource(CancellationToken userCancellationToken)
|
|
|
|
|
{
|
|
|
|
|
return new LinkedCancellationTokenSource(_cancellationToken, userCancellationToken);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private readonly struct LinkedCancellationTokenSource : IDisposable
|
|
|
|
|
{
|
|
|
|
|
private readonly CancellationTokenSource _cancellationTokenSource;
|
|
|
|
|
|
|
|
|
|
public LinkedCancellationTokenSource(CancellationToken token1, CancellationToken token2)
|
|
|
|
|
{
|
|
|
|
|
if (token1.CanBeCanceled && token2.CanBeCanceled)
|
|
|
|
|
{
|
|
|
|
|
_cancellationTokenSource = CancellationTokenSource.CreateLinkedTokenSource(token1, token2);
|
|
|
|
|
Token = _cancellationTokenSource.Token;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
_cancellationTokenSource = null;
|
|
|
|
|
Token = token1.CanBeCanceled ? token1 : token2;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public CancellationToken Token { get; }
|
|
|
|
|
|
|
|
|
|
public void Dispose()
|
|
|
|
|
{
|
|
|
|
|
_cancellationTokenSource?.Dispose();
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-03-22 21:18:45 -07:00
|
|
|
}
|
|
|
|
|
|
2022-03-09 03:40:00 +08:00
|
|
|
internal sealed class PeekableStreamReader : TextReader
|
2018-07-09 23:51:49 +10:00
|
|
|
{
|
2020-04-01 03:45:27 +01:00
|
|
|
private readonly Queue<string> _buffer;
|
|
|
|
|
private readonly StreamReader _inner;
|
2020-03-22 21:18:45 -07:00
|
|
|
|
2020-04-01 03:45:27 +01:00
|
|
|
public PeekableStreamReader(Stream stream)
|
2018-07-09 23:51:49 +10:00
|
|
|
{
|
|
|
|
|
_buffer = new Queue<string>();
|
2020-04-01 03:45:27 +01:00
|
|
|
_inner = new StreamReader(stream);
|
2018-07-09 23:51:49 +10:00
|
|
|
}
|
|
|
|
|
|
2020-04-01 03:45:27 +01:00
|
|
|
public override string ReadLine() => throw new NotImplementedException();
|
2020-03-22 21:18:45 -07:00
|
|
|
|
2018-07-09 23:51:49 +10:00
|
|
|
public override Task<string> ReadLineAsync()
|
|
|
|
|
{
|
|
|
|
|
if (_buffer.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
return Task.FromResult(_buffer.Dequeue());
|
|
|
|
|
}
|
2020-03-22 21:18:45 -07:00
|
|
|
|
2020-04-01 03:45:27 +01:00
|
|
|
return _inner.ReadLineAsync();
|
2018-07-09 23:51:49 +10:00
|
|
|
}
|
2020-03-22 21:18:45 -07:00
|
|
|
|
2018-07-09 23:51:49 +10:00
|
|
|
public async Task<string> PeekLineAsync()
|
|
|
|
|
{
|
2020-03-19 04:54:44 +00:00
|
|
|
var line = await ReadLineAsync().ConfigureAwait(false);
|
2018-07-09 23:51:49 +10:00
|
|
|
_buffer.Enqueue(line);
|
|
|
|
|
return line;
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-22 21:18:45 -07:00
|
|
|
public override int Read() => throw new NotImplementedException();
|
2018-07-09 23:51:49 +10:00
|
|
|
|
2020-03-22 21:18:45 -07:00
|
|
|
public override int Read(char[] buffer, int index, int count) => throw new NotImplementedException();
|
|
|
|
|
|
2020-04-23 11:40:06 -07:00
|
|
|
public override Task<int> ReadAsync(char[] buffer, int index, int count) =>
|
|
|
|
|
throw new NotImplementedException();
|
2020-03-22 21:18:45 -07:00
|
|
|
|
|
|
|
|
public override int ReadBlock(char[] buffer, int index, int count) => throw new NotImplementedException();
|
|
|
|
|
|
2020-04-23 11:40:06 -07:00
|
|
|
public override Task<int> ReadBlockAsync(char[] buffer, int index, int count) =>
|
|
|
|
|
throw new NotImplementedException();
|
2020-03-22 21:18:45 -07:00
|
|
|
|
|
|
|
|
public override string ReadToEnd() => throw new NotImplementedException();
|
|
|
|
|
|
|
|
|
|
public override Task<string> ReadToEndAsync() => throw new NotImplementedException();
|
2020-04-01 03:45:27 +01:00
|
|
|
|
|
|
|
|
protected override void Dispose(bool disposing)
|
|
|
|
|
{
|
|
|
|
|
if (disposing)
|
|
|
|
|
{
|
|
|
|
|
_inner.Dispose();
|
|
|
|
|
}
|
2020-04-23 11:40:06 -07:00
|
|
|
|
2020-04-01 03:45:27 +01:00
|
|
|
base.Dispose(disposing);
|
|
|
|
|
}
|
2018-09-27 10:50:39 -07:00
|
|
|
}
|
2018-07-09 23:51:49 +10:00
|
|
|
}
|
|
|
|
|
}
|