From 0bc0c28fbabfc842fb2768d2d7196b28b380d842 Mon Sep 17 00:00:00 2001 From: Morten Nielsen Date: Wed, 29 Jul 2020 17:09:25 -0700 Subject: [PATCH] Adds EndOfStreamReached event for buffered streams and better handle streams that can't auto-rewind Fixes #73 --- src/NmeaParser/BufferedStreamDevice.cs | 31 +++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/NmeaParser/BufferedStreamDevice.cs b/src/NmeaParser/BufferedStreamDevice.cs index da55a95..8980a7f 100644 --- a/src/NmeaParser/BufferedStreamDevice.cs +++ b/src/NmeaParser/BufferedStreamDevice.cs @@ -61,9 +61,20 @@ namespace NmeaParser var stream = await GetStreamAsync().ConfigureAwait(false); StreamReader sr = new StreamReader(stream); m_stream = new BufferedStream(sr, emulationSettings); + m_stream.EndOfStreamReached += OnEndOfStreamReached; return m_stream; } + private void OnEndOfStreamReached(object sender, EventArgs e) + { + EndOfStreamReached?.Invoke(this, e); + if (m_stream is BufferedStream stream && !stream.CanRewind && IsOpen) + { + // If we can't rewind the stream, stop + _ = CloseAsync(); + } + } + /// /// Gets or sets the emulated baud rate. Defaults to 115200 /// @@ -107,7 +118,11 @@ namespace NmeaParser /// protected override Task CloseStreamAsync(System.IO.Stream stream) { - m_stream?.Dispose(); + if (m_stream != null) + { + m_stream.EndOfStreamReached -= OnEndOfStreamReached; + m_stream?.Dispose(); + } return Task.FromResult(true); } @@ -134,6 +149,11 @@ namespace NmeaParser EmptyLine } + /// + /// Raised when the stream has reached the end. If the stream can be revound, it'll start over, unless you stop the device in this thread. + /// + public event EventHandler? EndOfStreamReached; + // stream that slowly populates a buffer from a StreamReader to simulate nmea messages coming // in lastLineRead by lastLineRead at a steady stream private class BufferedStream : Stream @@ -159,6 +179,8 @@ namespace NmeaParser m_readTask = StartReadLoop(m_tcs.Token); } + internal bool CanRewind => m_sr.BaseStream.CanSeek; + private async Task StartReadLoop(CancellationToken cancellationToken) { await Task.Yield(); @@ -230,7 +252,12 @@ namespace NmeaParser if (m_tcs.IsCancellationRequested) return null; if (m_sr.EndOfStream) + { + EndOfStreamReached?.Invoke(this, EventArgs.Empty); + if (m_tcs.IsCancellationRequested) + return null; m_sr.BaseStream.Seek(0, SeekOrigin.Begin); //start over + } return m_sr.ReadLine() + '\n'; } @@ -295,6 +322,8 @@ namespace NmeaParser m_sr.Dispose(); base.Dispose(disposing); } + + internal event EventHandler? EndOfStreamReached; } } }