openwebrx-clone/csdr/module/__init__.py

137 lines
3.4 KiB
Python
Raw Normal View History

2021-09-06 13:05:33 +00:00
from pycsdr.modules import Module as BaseModule
from pycsdr.modules import Reader, Writer
from pycsdr.types import Format
from abc import ABCMeta, abstractmethod
2021-09-06 18:00:14 +00:00
from threading import Thread
from io import BytesIO
2021-09-07 15:31:32 +00:00
from subprocess import Popen, PIPE
2021-09-08 11:47:46 +00:00
from functools import partial
2021-09-06 18:00:14 +00:00
import pickle
2021-09-06 13:05:33 +00:00
class Module(BaseModule, metaclass=ABCMeta):
def __init__(self):
self.reader = None
self.writer = None
super().__init__()
2021-09-06 13:05:33 +00:00
def setReader(self, reader: Reader) -> None:
self.reader = reader
2021-09-06 13:05:33 +00:00
def setWriter(self, writer: Writer) -> None:
self.writer = writer
2021-09-06 13:05:33 +00:00
@abstractmethod
def getInputFormat(self) -> Format:
pass
@abstractmethod
def getOutputFormat(self) -> Format:
pass
2021-09-06 18:00:14 +00:00
def pump(self, read, write):
def copy():
while True:
data = None
try:
data = read()
except ValueError:
pass
2021-09-30 21:04:59 +00:00
except BrokenPipeError:
break
if data is None or isinstance(data, bytes) and len(data) == 0:
break
write(data)
return copy
2021-09-06 18:00:14 +00:00
2021-09-07 12:45:52 +00:00
class AutoStartModule(Module, metaclass=ABCMeta):
2021-09-06 18:00:14 +00:00
def _checkStart(self) -> None:
if self.reader is not None and self.writer is not None:
self.start()
def setReader(self, reader: Reader) -> None:
super().setReader(reader)
self._checkStart()
def setWriter(self, writer: Writer) -> None:
super().setWriter(writer)
self._checkStart()
2021-09-07 12:45:52 +00:00
@abstractmethod
def start(self):
pass
class ThreadModule(AutoStartModule, Thread, metaclass=ABCMeta):
def __init__(self):
self.doRun = True
super().__init__()
Thread.__init__(self)
2021-09-06 18:00:14 +00:00
@abstractmethod
def run(self):
pass
def stop(self):
self.doRun = False
self.reader.stop()
2021-09-07 12:45:52 +00:00
def start(self):
Thread.start(self)
2021-09-06 18:00:14 +00:00
class PickleModule(ThreadModule):
def getInputFormat(self) -> Format:
return Format.CHAR
def getOutputFormat(self) -> Format:
return Format.CHAR
def run(self):
while self.doRun:
data = self.reader.read()
if data is None:
self.doRun = False
break
io = BytesIO(data.tobytes())
try:
while True:
output = self.process(pickle.load(io))
if output is not None:
self.writer.write(pickle.dumps(output))
except EOFError:
pass
@abstractmethod
def process(self, input):
pass
2021-09-07 15:31:32 +00:00
class PopenModule(AutoStartModule, metaclass=ABCMeta):
def __init__(self):
self.process = None
super().__init__()
@abstractmethod
def getCommand(self):
pass
def _getProcess(self):
return Popen(self.getCommand(), stdin=PIPE, stdout=PIPE)
2021-09-07 15:31:32 +00:00
def start(self):
self.process = self._getProcess()
# resume in case the reader has been stop()ed before
self.reader.resume()
2021-09-07 15:31:32 +00:00
Thread(target=self.pump(self.reader.read, self.process.stdin.write)).start()
2021-09-08 11:47:46 +00:00
Thread(target=self.pump(partial(self.process.stdout.read, 1024), self.writer.write)).start()
2021-09-07 15:31:32 +00:00
def stop(self):
if self.process is not None:
self.process.terminate()
self.process.wait()
self.process = None
self.reader.stop()