import os, threading
import socketserver as SocketServer
from .. drivers.return_codes import RETURN_CODES
from . network import CMDTYPE
from .. util import log
[docs]class ThreadedDataHandler(SocketServer.BaseRequestHandler):
[docs] def handle(self):
try:
cmd = ord(self.request.recv(1))
r = bytes(self.request.recv(2))
size = (ord(r[1]) << 8) | ord(r[0])
if cmd == CMDTYPE.PIXEL_DATA:
data = bytearray()
empty_count = 0
while len(data) < size:
buf = self.request.recv(4096)
if len(buf) == 0:
empty_count += 1
if empty_count >= 5:
log.exception(
"Failed to receive expected amount of data! "
"Expected: %s bytes / Received: %s bytes",
size, len(data))
self.request.sendall(RETURN_CODES.ERROR_SIZE)
return
data.extend(buf)
if len(data) != size:
log.exception(
"Received data size incorrect! "
"Expected: %s bytes / Received: {%s bytes",
size, len(data))
return
self.server.update(data)
if self.server.hasFrame:
while self.server.hasFrame():
pass
packet = bytearray()
packet.append(RETURN_CODES.SUCCESS)
self.request.sendall(packet)
elif cmd == CMDTYPE.BRIGHTNESS:
res = self.request.recv(1)
bright = ord(res)
result = RETURN_CODES.ERROR_UNSUPPORTED
if self.server.set_brightness:
if self.server.set_brightness(bright):
result = RETURN_CODES.SUCCESS
else:
# Try again.
self.server.set_brightness(bright)
packet = bytearray()
packet.append(result)
self.request.sendall(packet)
except Exception as e:
log.exception(e)
pass # if there's a comm error, just move on
return
[docs]class ThreadedDataServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
update = None
set_brightness = None
hasFrame = None
[docs]class NetworkReceiver:
def __init__(self, layout, port=3142, interface='0.0.0.0'):
self.layout = layout
self.address = (interface, port)
SocketServer.TCPServer.allow_reuse_address = True
self._server = ThreadedDataServer(self.address, ThreadedDataHandler)
self._server.update = self.update
self._server.set_brightness = self.layout.set_brightness
[docs] def start(self, join=False):
self._t = threading.Thread(target=self._server.serve_forever)
self._t.setDaemon(True) # don't hang on exit
self._t.start()
log.info("Listening on %s", self.address)
if join:
self._t.join()
[docs] def stop(self):
log.info("Closing server...")
self._server.shutdown()
self._server.server_close()
# self._t.join()
[docs] def update(self, data):
self.layout.setBuffer(list(data))
self.layout.push_to_driver()