Remove stream-like functionality from ContentReader/Writer
Use streams instead
This commit is contained in:
@@ -1,80 +0,0 @@
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public class ContentAccessStream : Stream
|
||||
{
|
||||
private readonly IContentReader? _contentReader;
|
||||
private readonly IContentWriter? _contentWriter;
|
||||
public override bool CanRead => _contentReader != null;
|
||||
|
||||
public override bool CanSeek => _contentReader != null;
|
||||
|
||||
public override bool CanWrite => _contentWriter != null;
|
||||
|
||||
public override long Length => throw new NotImplementedException();
|
||||
|
||||
public override long Position
|
||||
{
|
||||
get => throw new NotImplementedException();
|
||||
set => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public ContentAccessStream(IContentReader contentReader)
|
||||
{
|
||||
_contentReader = contentReader;
|
||||
}
|
||||
|
||||
public ContentAccessStream(IContentWriter contentWriter)
|
||||
{
|
||||
_contentWriter = contentWriter;
|
||||
}
|
||||
|
||||
public override void Flush()
|
||||
{
|
||||
if (_contentWriter == null) throw new NotSupportedException();
|
||||
Task.Run(async () => await _contentWriter.FlushAsync()).Wait();
|
||||
}
|
||||
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_contentReader == null) throw new IOException("This stream is not readable");
|
||||
var dataTask = Task.Run(async () => await _contentReader.ReadBytesAsync(count, offset));
|
||||
dataTask.Wait();
|
||||
var data = dataTask.Result;
|
||||
|
||||
if (data.Length > count) throw new Exception("More bytes has been read than requested");
|
||||
Array.Copy(data, buffer, data.Length);
|
||||
return data.Length;
|
||||
}
|
||||
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
if (_contentReader == null) throw new NotSupportedException();
|
||||
|
||||
var newPosition = origin switch
|
||||
{
|
||||
SeekOrigin.Begin => offset,
|
||||
SeekOrigin.Current => _contentReader.Position ?? 0 + offset,
|
||||
_ => throw new NotSupportedException()
|
||||
};
|
||||
_contentReader.SetPosition(newPosition);
|
||||
return newPosition;
|
||||
}
|
||||
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public override void Write(byte[] buffer, int offset, int count)
|
||||
{
|
||||
if (_contentWriter == null) throw new NotSupportedException();
|
||||
var data = buffer;
|
||||
if (buffer.Length != count)
|
||||
{
|
||||
data = new byte[count];
|
||||
Array.Copy(buffer, data, count);
|
||||
}
|
||||
|
||||
Task.Run(async () => await _contentWriter.WriteBytesAsync(data, offset)).Wait();
|
||||
}
|
||||
}
|
||||
@@ -7,8 +7,6 @@ namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public interface IContentProvider : IContainer, IOnContainerEnter
|
||||
{
|
||||
bool SupportsContentStreams { get; }
|
||||
|
||||
Task<IItem> GetItemByFullNameAsync(
|
||||
FullName fullName,
|
||||
PointInTime pointInTime,
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public interface IContentReader : IDisposable
|
||||
public interface IContentReader : IStreamContainer
|
||||
{
|
||||
int PreferredBufferSize { get; }
|
||||
long? Position { get; }
|
||||
|
||||
Task<byte[]> ReadBytesAsync(int bufferSize, int? offset = null);
|
||||
void SetPosition(long position);
|
||||
Stream AsStream();
|
||||
}
|
||||
@@ -1,10 +1,5 @@
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public interface IContentWriter : IDisposable
|
||||
public interface IContentWriter : IStreamContainer
|
||||
{
|
||||
int PreferredBufferSize { get; }
|
||||
|
||||
Task WriteBytesAsync(byte[] data, int? index = null, CancellationToken cancellationToken = default);
|
||||
Task FlushAsync(CancellationToken cancellationToken = default);
|
||||
Stream AsStream();
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace FileTime.Core.ContentAccess;
|
||||
|
||||
public interface IStreamContainer : IDisposable
|
||||
{
|
||||
Stream GetStream();
|
||||
}
|
||||
@@ -7,44 +7,14 @@ namespace FileTime.Core.CommandHandlers;
|
||||
|
||||
public class StreamCopyCommandHandler : ICommandHandler
|
||||
{
|
||||
private readonly IContentProviderRegistry _contentProviderRegistry;
|
||||
private readonly IContentAccessorFactory _contentAccessorFactory;
|
||||
|
||||
public StreamCopyCommandHandler(
|
||||
IContentProviderRegistry contentProviderRegistry,
|
||||
IContentAccessorFactory contentAccessorFactory)
|
||||
public StreamCopyCommandHandler(IContentAccessorFactory contentAccessorFactory)
|
||||
{
|
||||
_contentProviderRegistry = contentProviderRegistry;
|
||||
_contentAccessorFactory = contentAccessorFactory;
|
||||
}
|
||||
|
||||
public async Task<bool> CanHandleAsync(ICommand command)
|
||||
{
|
||||
if (command is not CopyCommand copyCommand) return false;
|
||||
|
||||
var targetSupportsContentStream =
|
||||
(await _contentProviderRegistry
|
||||
.ContentProviders
|
||||
.ToAsyncEnumerable()
|
||||
.FirstOrDefaultAwaitAsync(async p => await p.CanHandlePathAsync(copyCommand.Target))
|
||||
)?.SupportsContentStreams ?? false;
|
||||
|
||||
var allSourcesSupportsContentStream =
|
||||
(await copyCommand
|
||||
.Sources
|
||||
.ToAsyncEnumerable()
|
||||
.SelectAwait(s =>
|
||||
_contentProviderRegistry
|
||||
.ContentProviders
|
||||
.ToAsyncEnumerable()
|
||||
.FirstOrDefaultAwaitAsync(async p => await p.CanHandlePathAsync(s))
|
||||
)
|
||||
.ToListAsync()
|
||||
)
|
||||
.All(p => p?.SupportsContentStreams ?? false);
|
||||
|
||||
return targetSupportsContentStream && allSourcesSupportsContentStream;
|
||||
}
|
||||
public Task<bool> CanHandleAsync(ICommand command) => Task.FromResult(command is CopyCommand);
|
||||
|
||||
public async Task ExecuteAsync(ICommand command)
|
||||
{
|
||||
@@ -53,7 +23,7 @@ public class StreamCopyCommandHandler : ICommandHandler
|
||||
await copyCommand.ExecuteAsync(CopyElement);
|
||||
}
|
||||
|
||||
public async Task CopyElement(AbsolutePath sourcePath, AbsolutePath targetPath, CopyCommandContext copyCommandContext)
|
||||
private async Task CopyElement(AbsolutePath sourcePath, AbsolutePath targetPath, CopyCommandContext copyCommandContext)
|
||||
{
|
||||
if (copyCommandContext.CancellationToken.IsCancellationRequested) return;
|
||||
|
||||
@@ -72,25 +42,25 @@ public class StreamCopyCommandHandler : ICommandHandler
|
||||
using var reader = await _contentAccessorFactory.GetContentReaderFactory(source.Provider).CreateContentReaderAsync(source);
|
||||
using var writer = await _contentAccessorFactory.GetContentWriterFactory(target.Provider).CreateContentWriterAsync(target);
|
||||
|
||||
byte[] dataRead;
|
||||
var readerStream = reader.GetStream();
|
||||
var writerStream = writer.GetStream();
|
||||
|
||||
var dataRead = new byte[1024 * 1024];
|
||||
long currentProgress = 0;
|
||||
|
||||
do
|
||||
while (true)
|
||||
{
|
||||
if (copyCommandContext.CancellationToken.IsCancellationRequested) return;
|
||||
dataRead = await reader.ReadBytesAsync(writer.PreferredBufferSize);
|
||||
if (dataRead.Length > 0)
|
||||
{
|
||||
await writer.WriteBytesAsync(dataRead, cancellationToken: copyCommandContext.CancellationToken);
|
||||
await writer.FlushAsync(copyCommandContext.CancellationToken);
|
||||
currentProgress += dataRead.LongLength;
|
||||
if (copyCommandContext.CurrentProgress is not null)
|
||||
{
|
||||
copyCommandContext.CurrentProgress.SetProgressSafe(currentProgress);
|
||||
}
|
||||
var readLength = await readerStream.ReadAsync(dataRead);
|
||||
var actualDataRead = dataRead[..readLength];
|
||||
if (actualDataRead.Length == 0) break;
|
||||
|
||||
await copyCommandContext.UpdateProgressAsync();
|
||||
}
|
||||
} while (dataRead.Length > 0);
|
||||
await writerStream.WriteAsync(actualDataRead, cancellationToken: copyCommandContext.CancellationToken);
|
||||
await writerStream.FlushAsync(copyCommandContext.CancellationToken);
|
||||
currentProgress += actualDataRead.LongLength;
|
||||
copyCommandContext.CurrentProgress?.SetProgressSafe(currentProgress);
|
||||
|
||||
await copyCommandContext.UpdateProgressAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user