#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Fenrir TTY screen reader # By Chrys, Storm Dragon, and contributors. import os import os.path import select import socket from fenrirscreenreader.core import debug from fenrirscreenreader.core.eventData import FenrirEventType from fenrirscreenreader.core.remoteDriver import RemoteDriver as remoteDriver class driver(remoteDriver): def __init__(self): remoteDriver.__init__(self) def initialize(self, environment): self.env = environment # Use threading instead of multiprocessing to avoid pickle issues # with self.env (which contains unpicklable file handles) self.env["runtime"]["ProcessManager"].add_custom_event_thread( self.watch_dog, multiprocess=False ) def watch_dog(self, active, event_queue): # echo "command say this is a test" | nc localhost 22447 self.fenrirSock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.fenrirSock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.fenrirSock.settimeout(5.0) # Prevent hanging on slow clients self.host = "127.0.0.1" self.port = self.env["runtime"]["SettingsManager"].get_setting_as_int( "remote", "port" ) self.fenrirSock.bind((self.host, self.port)) self.fenrirSock.listen(1) while active.value: try: r, _, _ = select.select([self.fenrirSock], [], [], 0.8) except select.error: break if r == []: continue if self.fenrirSock in r: client_sock, client_addr = self.fenrirSock.accept() # Ensure client socket is always closed to prevent resource # leaks try: try: rawdata = client_sock.recv(8129) except Exception as e: self.env["runtime"]["DebugManager"].write_debug_out( "tcpDriver watch_dog: Error receiving data from " "client: " + str(e), debug.DebugLevel.ERROR, ) rawdata = b"" # Set default empty data if recv fails try: data = rawdata.decode("utf-8").rstrip().lstrip() event_queue.put( {"Type": FenrirEventType.remote_incomming, "data": data} ) except Exception as e: self.env["runtime"]["DebugManager"].write_debug_out( "tcpDriver watch_dog: Error decoding/queuing data: " + str(e), debug.DebugLevel.ERROR, ) finally: # Always close client socket, even if data processing fails try: client_sock.close() except Exception as e: self.env["runtime"]["DebugManager"].write_debug_out( "tcpDriver watch_dog: Error closing client socket: " + str(e), debug.DebugLevel.ERROR, ) if self.fenrirSock: self.fenrirSock.close() self.fenrirSock = None