summaryrefslogtreecommitdiff
path: root/voctocore/lib/controlserver.py
blob: e11d6a8756418d81d2c0d4b6db3486586f5770ef (plain)
  1. import socket, threading, queue
  2. from gi.repository import GObject
  3. def controlServerEntrypoint(f):
  4. # mark the method as something that requires view's class
  5. f.is_control_server_entrypoint = True
  6. return f
  7. class ControlServer():
  8. def __init__(self, videomix):
  9. '''Initialize server and start listening.'''
  10. self.videomix = videomix
  11. sock = socket.socket()
  12. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  13. sock.bind(('0.0.0.0', 23000))
  14. sock.listen(1)
  15. # register socket for callback inside the GTK-Mainloop
  16. GObject.io_add_watch(sock, GObject.IO_IN, self.listener)
  17. def listener(self, sock, *args):
  18. '''Asynchronous connection listener. Starts a handler for each connection.'''
  19. conn, addr = sock.accept()
  20. print("Connection from ", addr)
  21. # register data-received handler inside the GTK-Mainloop
  22. GObject.io_add_watch(conn, GObject.IO_IN, self.handler)
  23. return True
  24. def handler(self, conn, *args):
  25. '''Asynchronous connection handler. Processes each line from the socket.'''
  26. line = conn.recv(4096)
  27. if not len(line):
  28. print("Connection closed.")
  29. return False
  30. r = self.processLine(line.decode('utf-8'))
  31. if isinstance(r, str):
  32. conn.send((r+'\n').encode('utf-8'))
  33. return False
  34. conn.send('OK\n'.encode('utf-8'))
  35. return True
  36. def processLine(self, line):
  37. command, argstring = (line.strip()+' ').split(' ', 1)
  38. args = argstring.strip().split()
  39. print(command, args)
  40. if not hasattr(self.videomix, command):
  41. return 'unknown command {}'.format(command)
  42. f = getattr(self.videomix, command)
  43. if not hasattr(f, 'is_control_server_entrypoint'):
  44. return 'method {} not callable from controlserver'.format(command)
  45. try:
  46. return f(*args)
  47. except Exception as e:
  48. return str(e)