1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
|
import logging
from mopidy_mpd import dispatcher, formatting, network, protocol
from mopidy_mpd.protocol import tagtype_list
logger = logging.getLogger(__name__)
class MpdSession(network.LineProtocol):
"""
The MPD client session. Keeps track of a single client session. Any
requests from the client is passed on to the MPD request dispatcher.
"""
terminator = protocol.LINE_TERMINATOR
encoding = protocol.ENCODING
delimiter = rb"\r?\n"
def __init__(self, connection, config=None, core=None, uri_map=None):
super().__init__(connection)
self.dispatcher = dispatcher.MpdDispatcher(
session=self, config=config, core=core, uri_map=uri_map
)
self.tagtypes = tagtype_list.TAGTYPE_LIST.copy()
def on_start(self):
logger.info("New MPD connection from %s", self.connection)
self.send_lines([f"OK MPD {protocol.VERSION}"])
def on_line_received(self, line):
logger.debug("Request from %s: %s", self.connection, line)
# All mpd commands start with a lowercase alphabetic character
# To prevent CSRF attacks, requests starting with an invalid
# character are immediately dropped.
if len(line) == 0 or not (line[0].islower() and line[0].isalpha()):
self.connection.stop("Malformed command")
return
response = self.dispatcher.handle_request(line)
if not response:
return
logger.debug(
"Response to %s: %s",
self.connection,
formatting.indent(self.decode(self.terminator).join(response)),
)
self.send_lines(response)
def on_event(self, subsystem):
self.dispatcher.handle_idle(subsystem)
def decode(self, line):
try:
return super().decode(line)
except ValueError:
logger.warning(
"Stopping actor due to unescaping error, data "
"supplied by client was not valid."
)
self.stop()
def close(self):
self.stop()
|