Host: Made rendering pipeline a bit more flexible
This commit is contained in:
parent
330e1eb20e
commit
fefb33736a
8 changed files with 123 additions and 94 deletions
|
|
@ -1,12 +1,14 @@
|
|||
#!/usr/bin/env python
|
||||
|
||||
import socket
|
||||
from time import strftime
|
||||
import time
|
||||
import itertools
|
||||
import sys
|
||||
from contextlib import suppress
|
||||
import asyncio
|
||||
import threading
|
||||
|
||||
from config import *
|
||||
import config
|
||||
|
||||
import matelight
|
||||
import bdf
|
||||
|
|
@ -14,48 +16,48 @@ import crap
|
|||
|
||||
|
||||
def log(*args):
|
||||
print(strftime('\x1B[93m[%m-%d %H:%M:%S]\x1B[0m'), ' '.join(str(arg) for arg in args), '\x1B[0m')
|
||||
print(time.strftime('\x1B[93m[%m-%d %H:%M:%S]\x1B[0m'), ' '.join(str(arg) for arg in args), '\x1B[0m')
|
||||
sys.stdout.flush()
|
||||
|
||||
class TextRenderer:
|
||||
def __init__(self, text):
|
||||
def __init__(self, text, title='default', font=bdf.unifont):
|
||||
self.text = text
|
||||
self.width, _ = unifont.compute_text_bounds(text)
|
||||
self.font = font
|
||||
(self.width, _), _testrender = font.compute_text_bounds(text), font.render_text(text, 0)
|
||||
self.title = title
|
||||
|
||||
def __iter__(self):
|
||||
for i in range(-DISPLAY_WIDTH, self.width):
|
||||
yield render_text(self.text, i)
|
||||
for i in range(-config.display_width, self.width):
|
||||
yield self.title, self.font.render_text(self.text, i)
|
||||
time.sleep(0.05)
|
||||
|
||||
class MatelightTCPServer:
|
||||
def __init__(self, port, ip):
|
||||
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
||||
self.sock.setblocking(blocking)
|
||||
self.sock.bind((ip, port))
|
||||
self.conns = set()
|
||||
def __init__(self, ip, port, loop):
|
||||
coro = asyncio.start_server(self.handle_conn, ip, port, loop=loop)
|
||||
server = loop.run_until_complete(coro)
|
||||
self.renderqueue = []
|
||||
self.close = server.close
|
||||
|
||||
def __iter__(self):
|
||||
q, self.renderqueue = self.renderqueue, []
|
||||
for frame in itertools.chain(*q):
|
||||
yield frame
|
||||
for title, frame in itertools.chain(*q):
|
||||
yield title, frame
|
||||
|
||||
def handle_connections(self):
|
||||
for conn in self.conns:
|
||||
async def handle_conn(self, reader, writer):
|
||||
line = (await reader.read(1024)).decode('UTF-8').strip()
|
||||
if len(line) > 140: # Unicode string length, *not* byte length of encoded UTF-8
|
||||
writer.write(b'TOO MUCH INFORMATION!\n')
|
||||
else:
|
||||
addr,*rest = writer.get_extra_info('peername')
|
||||
log('\x1B[95mText from\x1B[0m {}: {}\x1B[0m'.format(addr, line))
|
||||
try:
|
||||
line = conn.recv(1024).decode('UTF-8').strip()
|
||||
if len(data) > 140: # Unicode string length, *not* byte length of encoded UTF-8
|
||||
conn.sendall(b'TOO MUCH INFORMATION!\n')
|
||||
else:
|
||||
log('\x1B[95mText from\x1B[0m {}: {}\x1B[0m'.format(addr, data))
|
||||
renderqueue.append(TextRenderer(data))
|
||||
conn.sendall(b'KTHXBYE!\n')
|
||||
except socket.error, e:
|
||||
if err == errno.EAGAIN or err == errno.EWOULDBLOCK:
|
||||
continue
|
||||
with suppress(socket.error):
|
||||
conn.close()
|
||||
self.conns.remove(conn)
|
||||
self.renderqueue.append(TextRenderer(line, title='tcp:'+addr))
|
||||
except:
|
||||
writer.write(b'STAHPTROLLINK?\n')
|
||||
else:
|
||||
writer.write(b'KTHXBYE!\n')
|
||||
await writer.drain()
|
||||
writer.close()
|
||||
|
||||
def _fallbackiter(it, fallback):
|
||||
for fel in fallback:
|
||||
|
|
@ -63,19 +65,32 @@ def _fallbackiter(it, fallback):
|
|||
yield el
|
||||
yield fel
|
||||
|
||||
def defaulttexts(filename='default.lines'):
|
||||
with open(filename) as f:
|
||||
return itertools.chain.from_iterable(( TextRenderer(l[:-1].replace('\\x1B', '\x1B')) for l in f.readlines() ))
|
||||
|
||||
if __name__ == '__main__':
|
||||
tcp_server = MatelightTCPServer(config.tcp_addr, config.tcp_port)
|
||||
try:
|
||||
ml = matelight.Matelight(config.ml_usb_serial_match)
|
||||
except ValueError as e:
|
||||
print(e, 'Starting in headless mode.', file=sys.stderr)
|
||||
ml = None
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
tcp_server = MatelightTCPServer(config.tcp_addr, config.tcp_port, loop)
|
||||
udp_server = crap.CRAPServer(config.udp_addr, config.udp_port)
|
||||
forwarder = crap.CRAPClient(config.crap_fw_addr, config.crap_fw_port) if config.crap_fw_addr is not None else None
|
||||
|
||||
def defaulttexts(filename='default.lines'):
|
||||
with open(filename) as f:
|
||||
return itertools.chain.from_iterable(( TextRenderer(l[:-1].replace('\\x1B', '\x1B')) for l in f.readlines() ))
|
||||
async_thr = threading.Thread(target=loop.run_forever)
|
||||
async_thr.daemon = True
|
||||
async_thr.start()
|
||||
|
||||
with suppress(KeyboardInterrupt):
|
||||
for renderer in _fallbackiter(tcp_server, defaulttexts()):
|
||||
for frame in _fallbackiter(udp_server, renderer):
|
||||
matelight.sendframe(frame)
|
||||
while True:
|
||||
for title, frame in _fallbackiter(udp_server, _fallbackiter(tcp_server, defaulttexts())):
|
||||
if ml:
|
||||
ml.sendframe(frame)
|
||||
if forwarder:
|
||||
forwarder.sendframe(frame)
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue