Commit f2a8adaf authored by Jonas Jelten's avatar Jonas Jelten

use streams instead of the asyncio protocol

parent e6141ecf
videoscreen - display received urls with mpv
Copyright (C) 2016 Jonas Jelten <jj@stusta.net>
Copyright (C) 2016-2017 Jonas Jelten <jj@stusta.net>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
......
# videoscreen systemd user service
[Unit]
Description=Videoscreen mpv server
After=network-online.target
[Service]
ExecStart=/usr/bin/python3 -m videoscreen -- --quiet
Restart=on-failure
[Install]
WantedBy=default.target
......@@ -8,6 +8,7 @@ import argparse
from . import VideoScreen
def main():
""" launch the screen """
......
"""
protocol definition for data reception
"""
import asyncio
class UrlReceiver(asyncio.Protocol):
"""
protocol for receiving the media url
"""
MAX_WAIT = 10
LINEBUF_MAX = 4096
def __init__(self, screen):
self.buf = bytearray()
self.screen = screen
self.transport = None
self.peername = None
self.timer = None
def connection_made(self, transport):
self.seq_nr = self.screen.get_play_id()
self.peername = transport.get_extra_info('peername')
self.transport = transport
loop = asyncio.get_event_loop()
self.timer = loop.call_later(self.MAX_WAIT, self.timeout)
def data_received(self, data):
if len(self.buf) + len(data) > self.LINEBUF_MAX:
self.transport.write(b"too much!\n")
self.close()
return
if not self.screen.is_newest_id(self.seq_nr):
self.transport.write(b"too slow!\n")
self.close()
return
self.buf += data
# a url is \n-terminated
npos = self.buf.find(b"\n")
if npos != -1:
self.timer.cancel()
self.transport.write(b"yay!\n")
self.transport.close()
data = self.buf[:npos]
self.screen.display(self.seq_nr, self.peername, data.decode())
def timeout(self):
""" no answer for some time """
self.transport.write(b"too late!\n")
def close(self):
""" cancel the timer and close the connection """
if self.timer:
self.timer.cancel()
self.transport.close()
def connection_lost(self, exc):
pass
......@@ -6,7 +6,6 @@ import asyncio
from .mpd import MPD
from .player import Player
from .urlreceiver import UrlReceiver
MPV_INVOCATION = ["mpv"]
......@@ -48,7 +47,7 @@ class VideoScreen:
"""
if not self.is_newest_id(seq_nr):
raise Exception("can't play too old id")
raise Exception("can't play used connection id")
self.last_played_seq_id = seq_nr
......@@ -74,14 +73,50 @@ class VideoScreen:
if self.control_mpd and self.mpd_was_playing:
self.mpd.play()
async def process_command(self, cmd, connection_id, peer_id):
"""
Process a command from a client
"""
command = cmd.decode(errors="ignore")
if False:
raise NotImplementedError("more commands")
else:
self.display(connection_id, peer_id, cmd.strip())
return b"yay!\n"
async def new_client(self, reader, writer):
"""
Called when a new client connects to the server.
"""
conn_id = self.get_play_id()
peer_id = writer.get_extra_info("peername")
while True:
command = await reader.readline()
if not command:
reader.feed_eof()
writer.close()
break
try:
result = await self.process_command(command, conn_id, peer_id)
writer.write(result)
except Exception as exc:
writer.write(("error: %s\n" % exc).encode())
def launch(self):
""" run the videoscreen """
print("launching on {}:{}...".format(self.address, self.port))
loop = asyncio.get_event_loop()
coro = loop.create_server(lambda: UrlReceiver(self),
self.address, self.port)
coro = asyncio.start_server(self.new_client,
self.address, self.port)
server = loop.run_until_complete(coro)
try:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment