diff --git a/bombsquad_server b/bombsquad_server index ff30aaf..d92e1f0 100644 --- a/bombsquad_server +++ b/bombsquad_server @@ -11,10 +11,11 @@ import signal import subprocess import sys import time +import _thread from pathlib import Path from threading import Lock, Thread, current_thread from typing import TYPE_CHECKING - +from nbstreamreader import NonBlockingStreamReader as NBSR # We make use of the bacommon and efro packages as well as site-packages # included with our bundled Ballistica dist, so we need to add those paths # before we import them. @@ -99,7 +100,7 @@ class ServerManagerApp: self._subprocess_sent_unclean_exit = False self._subprocess_thread: Optional[Thread] = None self._subprocess_exited_cleanly: Optional[bool] = None - + self.nbsr=None # This may override the above defaults. self._parse_command_line_args() @@ -583,10 +584,17 @@ class ServerManagerApp: # Launch! try: + + self._subprocess = subprocess.Popen( - [binary_name, '-cfgdir', self._ba_root_path], - stdin=subprocess.PIPE, - cwd='dist') + [binary_name, '-cfgdir', self._ba_root_path ], + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd='dist') + + self.nbsr=NBSR(self._subprocess.stdout) + self.nbsrerr=NBSR(self._subprocess.stderr) except Exception as exc: self._subprocess_exited_cleanly = False print( @@ -596,6 +604,7 @@ class ServerManagerApp: # Do the thing. try: self._run_subprocess_until_exit() + except Exception as exc: print(f'{Clr.RED}Error running server subprocess: {exc}{Clr.RST}', flush=True) @@ -695,7 +704,7 @@ class ServerManagerApp: f' ba._servermode._cmd({val})\n').encode() self._subprocess.stdin.write(execcode) self._subprocess.stdin.flush() - + def _run_subprocess_until_exit(self) -> None: if self._subprocess is None: return @@ -713,7 +722,16 @@ class ServerManagerApp: # If the app is trying to shut down, nope out immediately. if self._done: break - + # output=self._subprocess.stdout.readline() + # print(output) + out=self.nbsr.readline(0.1) + out2=self.nbsrerr.readline(0.1) + if out: + sys.stdout.write(out.decode("utf-8") ) + _thread.start_new_thread(dump_logs,(out.decode("utf-8"),)) + if out2: + sys.stdout.write(out2.decode("utf-8") ) + _thread.start_new_thread(dump_logs,(out2.decode("utf-8"),)) # Pass along any commands to our process. with self._subprocess_commands_lock: for incmd in self._subprocess_commands: @@ -732,6 +750,7 @@ class ServerManagerApp: # If they want to force-kill our subprocess, simply exit this # loop; the cleanup code will kill the process if its still # alive. + if (self._subprocess_force_kill_time is not None and time.time() > self._subprocess_force_kill_time): print( @@ -864,7 +883,15 @@ def main() -> None: # Any others will bubble up and give us the usual mess. exc.pretty_print() sys.exit(1) +def dump_logs(msg): + if os.path.isfile('logs.log'): + size=os.path.getsize('logs.log') + + if size > 2000000: + os.remove('logs.log') + with open("logs.log","a") as f: + f.write(msg) if __name__ == '__main__': main() diff --git a/nbstreamreader.py b/nbstreamreader.py new file mode 100644 index 0000000..bcffcbb --- /dev/null +++ b/nbstreamreader.py @@ -0,0 +1,39 @@ +from threading import Thread +from queue import Queue, Empty + +class NonBlockingStreamReader: + + def __init__(self, stream): + ''' + stream: the stream to read from. + Usually a process' stdout or stderr. + ''' + + self._s = stream + self._q = Queue() + + def _populateQueue(stream, queue): + ''' + Collect lines from 'stream' and put them in 'quque'. + ''' + + while True: + line = stream.readline() + if line: + queue.put(line) + else: + raise UnexpectedEndOfStream + + self._t = Thread(target = _populateQueue, + args = (self._s, self._q)) + self._t.daemon = True + self._t.start() #start collecting lines from the stream + + def readline(self, timeout = None): + try: + return self._q.get(block = timeout is not None, + timeout = timeout) + except Empty: + return None + +class UnexpectedEndOfStream(Exception): pass \ No newline at end of file