summaryrefslogtreecommitdiff
path: root/voctogui/lib/connection.py
blob: 6f8245f8bd37ccbba51aa84887ba2ef2ae295438 (plain)
  1. import logging
  2. import socket
  3. import json
  4. import sys
  5. from queue import Queue
  6. from gi.repository import Gtk, GObject
  7. log = logging.getLogger('Connection')
  8. conn = None
  9. ip = None
  10. port = 9999
  11. command_queue = Queue()
  12. signal_handlers = {}
  13. def establish(host):
  14. global conn, port, log, ip
  15. log.info('establishing Connection to %s', host)
  16. conn = socket.create_connection( (host, port) )
  17. log.debug('Connection successful \o/')
  18. ip = conn.getpeername()[0]
  19. log.debug('Remote-IP is %s', ip)
  20. def fetchServerConfig():
  21. global conn, log
  22. log.info('reading server-config')
  23. fd = conn.makefile('rw')
  24. fd.write("get_config\n")
  25. fd.flush()
  26. while True:
  27. line = fd.readline()
  28. words = line.split(' ')
  29. signal = words[0]
  30. args = words[1:]
  31. if signal != 'server_config':
  32. continue
  33. server_config_json = " ".join(args)
  34. server_config = json.loads(server_config_json)
  35. return server_config
  36. def enterNonblockingMode():
  37. global conn, log
  38. log.debug('entering nonblocking-mode')
  39. conn.setblocking(False)
  40. GObject.io_add_watch(conn, GObject.IO_IN, on_data, [''])
  41. def on_data(conn, _, leftovers, *args):
  42. global log
  43. '''Asynchronous connection handler. Pushes data from socket
  44. into command queue linewise'''
  45. try:
  46. while True:
  47. try:
  48. leftovers.append(conn.recv(4096).decode(errors='replace'))
  49. if len(leftovers[-1]) == 0:
  50. log.info("Socket was closed")
  51. # FIXME try to reconnect
  52. conn.close()
  53. Gtk.main_quit()
  54. return False
  55. except UnicodeDecodeError as e:
  56. continue
  57. except:
  58. pass
  59. data = "".join(leftovers)
  60. del leftovers[:]
  61. lines = data.split('\n')
  62. for line in lines[:-1]:
  63. log.debug("got line: %r", line)
  64. line = line.strip()
  65. log.debug('re-starting on_loop scheduling')
  66. GObject.idle_add(on_loop)
  67. command_queue.put((line, conn))
  68. if lines[-1] != '':
  69. log.debug("remaining %r", lines[-1])
  70. leftovers.append(lines[-1])
  71. return True
  72. def on_loop():
  73. '''Command handler. Processes commands in the command queue whenever
  74. nothing else is happening (registered as GObject idle callback)'''
  75. global command_queue
  76. log.debug('on_loop called')
  77. if command_queue.empty():
  78. log.debug('command_queue is empty again, stopping on_loop scheduling')
  79. return False
  80. line, requestor = command_queue.get()
  81. words = line.split()
  82. if len(words) < 1:
  83. log.debug('command_queue is empty again, stopping on_loop scheduling')
  84. return True
  85. signal = words[0]
  86. args = words[1:]
  87. log.info('received signal %s, dispatching', signal)
  88. if signal not in signal_handlers:
  89. return True
  90. for handler in signal_handlers[signal]:
  91. cb = handler['cb']
  92. if 'one' in handler and handler['one']:
  93. log.debug('removing one-time handler')
  94. del signal_handlers[signal]
  95. cb(*args)
  96. return True
  97. def send(command, *args):
  98. global conn, log
  99. if len(args) > 0:
  100. command += ' '+(' '.join(args))
  101. command += '\n'
  102. conn.send(command.encode('ascii'))
  103. def on(signal, cb):
  104. if signal not in signal_handlers:
  105. signal_handlers[signal] = []
  106. signal_handlers[signal].append({'cb': cb})
  107. def one(signal, cb):
  108. if signal not in signal_handlers:
  109. signal_handlers[signal] = []
  110. signal_handlers[signal].append({'cb': cb, 'one': True})