X-Git-Url: https://git.kaliko.me/?p=python-musicpdaio.git;a=blobdiff_plain;f=mpdaio%2Fclient.py;h=2b971627e6d604dcd4046f524eb979c1d0cb34b2;hp=c37e0d6cc3946cb573104b23863519227c8d1a50;hb=HEAD;hpb=b1581f5d521911f847e20501c270c840b1eb6494 diff --git a/mpdaio/client.py b/mpdaio/client.py index c37e0d6..2b97162 100644 --- a/mpdaio/client.py +++ b/mpdaio/client.py @@ -11,7 +11,7 @@ from .exceptions import MPDConnectionError, MPDProtocolError, MPDCommandError from .utils import Range, escape from .const import CONNECTION_MAX, CONNECTION_TIMEOUT -from .const import ERROR_PREFIX, SUCCESS, NEXT +from .const import HELLO_PREFIX, ERROR_PREFIX, SUCCESS, NEXT log = logging.getLogger(__name__) @@ -37,10 +37,12 @@ class MPDClient: """ def __init__(self, host: str | None = None, - port: str | int | None = None, - password: str | None = None): + port: str | int | None = None, + password: str | None = None): #: Connection pool self._pool = ConnectionPool(max_connections=CONNECTION_MAX) + #: connection timeout + self.mpd_timeout = CONNECTION_TIMEOUT self._get_envvars() #: Host used to make connections (:py:obj:`str`) self.host = host or self.server_discovery[0] @@ -48,8 +50,6 @@ class MPDClient: self.pwd = password or self.server_discovery[2] #: port used with the current connection (:py:obj:`int`, :py:obj:`str`) self.port = port or self.server_discovery[1] - #: connection timeout - self.mpd_timeout = CONNECTION_TIMEOUT log.info('Using %s:%s to connect', self.host, self.port) def _get_envvars(self): @@ -267,7 +267,7 @@ class CmdHandler: "sendmessage": self._fetch_nothing, } self.command = None - self._command_list = None + self._command_list: list | None = None self.args = None self.pool = pool self.host = (server, port) @@ -295,17 +295,28 @@ class CmdHandler: return retval async def _init_connection(self): - """Init connection if needed""" + """Init connection if needed + + * Consumes the hello line and sets the protocol version + * Send password command if a password is provided + """ if not self.connection.version: - # TODO: move hello here instead of connection? - # Need to consume hello - pass + await self._hello() if self.password and not self.connection.auth: # Need to send password await self._write_command('password', [self.password]) await self._fetch_nothing() self.connection.auth = True + async def _hello(self) -> None: + """Consume HELLO_PREFIX""" + data = await self.connection.readuntil(b'\n') + rcv = data.decode('utf-8') + if not rcv.startswith(HELLO_PREFIX): + raise MPDProtocolError(f'Got invalid MPD hello: "{rcv}"') + log.debug('consumed hello prefix: %r', rcv) + self.connection.version = rcv.split('\n')[0][len(HELLO_PREFIX):] + async def _write_line(self, line): self.connection.write(f"{line!s}\n".encode()) await self.connection.drain() @@ -336,7 +347,7 @@ class CmdHandler: amount -= len(result) return bytes(chunk) - async def _read_line(self, binary=False): + async def _read_line(self): line = await self.connection.readline() line = line.decode('utf-8') if not line.endswith('\n'): @@ -355,8 +366,8 @@ class CmdHandler: return None return line - async def _read_pair(self, separator, binary=False): - line = await self._read_line(binary=binary) + async def _read_pair(self, separator): + line = await self._read_line() if line is None: return None pair = line.split(separator, 1) @@ -364,11 +375,11 @@ class CmdHandler: raise MPDProtocolError(f"Could not parse pair: '{line}'") return pair - async def _read_pairs(self, separator=": ", binary=False): - pair = await self._read_pair(separator, binary=binary) + async def _read_pairs(self, separator=": "): + pair = await self._read_pair(separator) while pair: yield pair - pair = await self._read_pair(separator, binary=binary) + pair = await self._read_pair(separator) async def _read_list(self): seen = None @@ -415,7 +426,7 @@ class CmdHandler: async def _fetch_nothing(self): line = await self._read_line() if line is not None: - raise ProtocolError(f"Got unexpected return value: '{line}'") + raise MPDProtocolError(f"Got unexpected return value: '{line}'") async def _fetch_item(self): pairs = [_ async for _ in self._read_pairs()] @@ -467,7 +478,7 @@ class CmdHandler: async def _fetch_composite(self): obj = {} - async for key, value in self._read_pairs(binary=True): + async for key, value in self._read_pairs(): key = key.lower() obj[key] = value if key == 'binary': @@ -487,10 +498,10 @@ class CmdHandler: raise ConnectionError('Error reading binary content: ' f'Expects {amount}B, got {data_bytes}') # Fetches trailing new line - await self._read_line(binary=True) + await self._read_line() #ALT: await self.connection.readuntil(b'\n') # Fetches SUCCESS code - await self._read_line(binary=True) + await self._read_line() #ALT: await self.connection.readuntil(b'OK\n') return obj