import io import sys import logging from datetime import datetime from collections import deque from edosl0util.stream import PacketStream, MissingPackets # date used as a flag value for comparissons _FLAG_DATE = datetime(1900, 1, 1) LOG = logging.getLogger(__name__) def _group_packets(stream): """ Returns a generator that yields all packets between timestamps. """ packet = stream.next() while not packet.stamp: yield packet packet = stream.next() # put the next packet with a stamp so it will be next stream.push_back(packet) def _is_valid_group(packets): return packets[0].is_first() \ and packets[-1].is_last() \ and packets[0].apid == packets[-1].apid def merge(streams, output=sys.stdout): last_apid = None last_stamp = datetime(1900, 1, 1) # streams are removed as they are exhausted while streams: for stream in streams: LOG.debug(stream) try: LOG.debug("seeking to %s, %s", last_stamp, last_apid) stream.seek(last_stamp, last_apid) while True: packets = deque() packet = stream.next() if packet.is_standalone(): packets.append(packet) else: # Collect all packets between packets with timestamps. # Missing packets and packets that form an invalid group # will be skipped. group = deque([packet]) group.extend(_group_packets(stream)) if _is_valid_group(group): packets.extend(group) elif group[0].is_first(): last_stamp = group[0].stamp last_apid = group[0].apid break else: # yield to next stream, perhaps they have a valid # group. LOG.debug("invalid group, switching streams:%s", group) break if not packets: continue # first packet always has a stamp because it's either standalone or # part of a valid group last_stamp = packets[0].stamp last_apid = packets[0].apid while packets: output.write(packets.popleft().blob) except MissingPackets as err: LOG.debug("missing packets, switching streams: %s", err.args) except StopIteration: streams.remove(stream) LOG.debug("end-of-stream %s", stream) continue