Add network repl to control the camp atmo

This commit is contained in:
Sebastian Lohff 2019-08-20 14:29:29 +02:00
parent d56ef5f64e
commit 87f6bf8e21
2 changed files with 86 additions and 0 deletions

83
atmorepl.py Normal file
View File

@ -0,0 +1,83 @@
#!/usr/bin/env python3
import socketserver
import threading
class WrongArgumentCount(Exception):
def __init__(self, command, expected, found):
if isinstance(expected, list):
expected = "{} to {}".format(**expected)
msg = "Command {} expects {} arguments, found {}".format(command, expected, found)
super(WrongArgumentCount, self).__init__(msg)
class CommandNotFound(Exception):
def __init__(self, command):
msg = "Command {} does not exist".format(command)
super(CommandNotFound, self).__init__(msg)
class AtmoClientHandler(socketserver.StreamRequestHandler):
def setup(self):
super(AtmoClientHandler, self).setup()
self.authenticated = True
self.quit = False
def handle(self):
try:
while not self.quit:
self.send(">>> ", end='')
data = self.rfile.readline().decode().strip()
tokens = data.split()
if len(tokens) > 0:
self.handle_command(tokens)
except BrokenPipeError:
print(" >> Client disconnected")
def handle_command(self, tokens):
cmd = tokens[0].lower()
args = tokens[1:]
try:
if cmd == "reload":
self._ensure_args(cmd, 0, args)
self.atmo.load_sounds()
self.send("Sounds reloaded")
elif cmd == "help":
self._ensure_args(cmd, 0, args)
self.send("The following commands are available: ")
self.send(" reload")
elif cmd == "exit":
self.quit = True
self.send("Bye")
else:
raise CommandNotFound(cmd)
except (CommandNotFound, WrongArgumentCount) as e:
self.send("Error: {}".format(e))
@staticmethod
def _ensure_args(cmd, expected, args):
if isinstance(expected, list):
if not expected[0] <= len(args) <= expected[1]:
raise WrongArgumentCount(cmd, expected, len(args))
else:
if len(args) != expected:
raise WrongArgumentCount(cmd, expected, len(args))
def send(self, line, end='\n'):
self.wfile.write("{}{}".format(line, end).encode())
class ReusableThreadingTCPServer(socketserver.ThreadingTCPServer):
daemon_threads = True
allow_reuse_address = True
class AtmoReplRunner(threading.Thread):
def __init__(self, atmo, host='0.0.0.0', port=7723):
super(AtmoReplRunner, self).__init__()
AtmoClientHandler.atmo = atmo
self._client = ReusableThreadingTCPServer((host, port), AtmoClientHandler)
self.daemon = True
def run(self):
self._client.serve_forever()

View File

@ -5,6 +5,7 @@ import random
from glob import glob from glob import glob
from pygame import mixer from pygame import mixer
from atmorepl import AtmoReplRunner
VERBOSITY = 0 VERBOSITY = 0
@ -80,6 +81,8 @@ class CampAtmo:
def main(): def main():
atmo = CampAtmo() atmo = CampAtmo()
atmoRepl = AtmoReplRunner(atmo, port=7723)
atmoRepl.start()
try: try:
atmo.run_forever() atmo.run_forever()
except KeyboardInterrupt: except KeyboardInterrupt: