refactor: refactor segment remuxer...

This commit is contained in:
acgnhik 2022-08-27 13:04:30 +08:00
parent ebf75ab487
commit 35ef14b31c
3 changed files with 50 additions and 18 deletions

View File

@ -52,15 +52,17 @@ def parse(
observer.on_next(tag) observer.on_next(tag)
stream.close() stream.close()
except EOFError as e: except EOFError as e:
logger.debug(f'Error occurred while parsing stream: {repr(e)}')
if complete_on_eof: if complete_on_eof:
observer.on_completed() observer.on_completed()
else: else:
if not ignore_eof: if not ignore_eof:
observer.on_error(e) observer.on_error(e)
except ValueError as e: except ValueError as e:
if ignore_value_error: logger.debug(
logger.debug(f'Error occurred while parsing stream: {repr(e)}') f'Error occurred while parsing stream: {repr(e)}', exc_info=e
else: )
if not ignore_value_error:
observer.on_error(e) observer.on_error(e)
except Exception as e: except Exception as e:
observer.on_error(e) observer.on_error(e)

View File

@ -7,6 +7,8 @@ from typing import Final, List, Optional, Union
import urllib3 import urllib3
from reactivex import Observable, abc from reactivex import Observable, abc
from reactivex.disposable import CompositeDisposable, Disposable, SerialDisposable from reactivex.disposable import CompositeDisposable, Disposable, SerialDisposable
from tenacity import Retrying, stop_after_delay, wait_fixed
from tenacity.retry import retry_if_not_exception_type
from blrec.bili.live import Live from blrec.bili.live import Live
from blrec.utils.io import wait_for from blrec.utils.io import wait_for
@ -69,12 +71,20 @@ class SegmentRemuxer:
if isinstance(data, InitSectionData): if isinstance(data, InitSectionData):
init_section_data = data.payload init_section_data = data.payload
segment_data_cache.clear() segment_data_cache.clear()
logger.debug('Stop stream remuxer for init section')
self._stream_remuxer.stop()
if self._stream_remuxer.exception and not self._stream_remuxer.stopped:
logger.debug(
'Stop stream remuxer due to '
+ repr(self._stream_remuxer.exception)
)
self._stream_remuxer.stop() self._stream_remuxer.stop()
try: try:
if self._stream_remuxer.stopped: if self._stream_remuxer.stopped:
while True:
self._stream_remuxer.start() self._stream_remuxer.start()
while True:
ready = self._stream_remuxer.wait(timeout=1) ready = self._stream_remuxer.wait(timeout=1)
if disposed: if disposed:
return return
@ -94,6 +104,7 @@ class SegmentRemuxer:
write(data.payload) write(data.payload)
except Exception as e: except Exception as e:
logger.warning(f'Failed to write data to stream remuxer: {repr(e)}') logger.warning(f'Failed to write data to stream remuxer: {repr(e)}')
logger.debug(f'Stop stream remuxer due to {repr(e)}')
self._stream_remuxer.stop() self._stream_remuxer.stop()
if len(segment_data_cache) >= self._MAX_SEGMENT_DATA_CACHE: if len(segment_data_cache) >= self._MAX_SEGMENT_DATA_CACHE:
segment_data_cache = segment_data_cache[ segment_data_cache = segment_data_cache[
@ -121,6 +132,10 @@ class SegmentRemuxer:
return Observable(subscribe) return Observable(subscribe)
class CloseRemuxedStream(Exception):
pass
class RemuxedStream(io.RawIOBase): class RemuxedStream(io.RawIOBase):
def __init__( def __init__(
self, stream_remuxer: StreamRemuxer, *, read_timeout: float = 10 self, stream_remuxer: StreamRemuxer, *, read_timeout: float = 10
@ -133,21 +148,27 @@ class RemuxedStream(io.RawIOBase):
if self._stream_remuxer.stopped: if self._stream_remuxer.stopped:
ready = self._stream_remuxer.wait(timeout=self._read_timeout) ready = self._stream_remuxer.wait(timeout=self._read_timeout)
if not ready: if not ready:
logger.debug( msg = f'Stream remuxer not ready in {self._read_timeout} seconds'
f'Stream remuxer not ready in {self._read_timeout} seconds' logger.debug(msg)
) raise EOFError(msg)
raise EOFError
try: try:
for attempt in Retrying(
reraise=True,
retry=retry_if_not_exception_type(TimeoutError),
wait=wait_fixed(1),
stop=stop_after_delay(self._read_timeout),
):
with attempt:
data = wait_for( data = wait_for(
self._stream_remuxer.output.read, self._stream_remuxer.output.read,
args=(size,), args=(size,),
timeout=self._read_timeout, timeout=self._read_timeout,
) )
except Exception as e: except Exception as exc:
logger.warning(f'Failed to read data from stream remuxer: {repr(e)}') logger.warning(f'Failed to read data from stream remuxer: {repr(exc)}')
self._stream_remuxer.stop() self._stream_remuxer.exception = exc
raise EOFError raise EOFError(exc)
else: else:
assert data is not None assert data is not None
self._offset += len(data) self._offset += len(data)
@ -157,4 +178,9 @@ class RemuxedStream(io.RawIOBase):
return self._offset return self._offset
def close(self) -> None: def close(self) -> None:
self._stream_remuxer.stop() if self._stream_remuxer.stopped:
return
if self._stream_remuxer.exception:
return
logger.debug('Close remuxed stream')
self._stream_remuxer.exception = CloseRemuxedStream()

View File

@ -55,6 +55,10 @@ class StreamRemuxer(StoppableMixin, SupportDebugMixin):
def exception(self) -> Optional[Exception]: def exception(self) -> Optional[Exception]:
return self._exception return self._exception
@exception.setter
def exception(self, exc: Exception) -> None:
self._exception = exc
def __enter__(self): # type: ignore def __enter__(self): # type: ignore
self.start() self.start()
self.wait() self.wait()