Pregunta

Estoy usando el módulo python-mpd2 para controlar un reproductor multimedia en una Raspberry Pi en una aplicación GUI.Por lo tanto, me gustaría manejar con elegancia los errores de conexión y los tiempos de espera (el reproductor en cuestión desconecta las conexiones MPD después de 60 segundos) en segundo plano.Sin embargo, el módulo MPD no tiene un único punto de entrada a través del cual se envíen todos los comandos o se recupere la información que pueda parchear.

Me gustaría una clase que permita el acceso a todos los mismos métodos que mpd.MPDClient, pero permítanme agregar mi propio manejo de errores.En otras palabras, si hago:

client.play()

Y se produce un error de conexión, me gustaría detectarlo y reenviar el mismo comando.Aparte del pequeño retraso causado por tener que volver a conectarse al servidor, el usuario no debería notar que nada anda mal.

Hasta ahora, esta es la solución que se me ocurrió.Está funcionando en mi aplicación, pero realmente no cumple mis objetivos.

from functools import partial
from mpd import MPDClient, ConnectionError

class PersistentMPDClient(object):
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.client = MPDClient()
        self.client.connect(self.host, self.port)

    def command(self, cmd, *args, **kwargs):
        command_callable = partial(self.client.__getattribute__(cmd), *args, **kwargs)
        try:
            return command_callable()
        except ConnectionError:
            # Mopidy drops our connection after a while, so reconnect to send the command
            self.client._soc = None
            self.client.connect(self.host, self.port)
            return command_callable()

Podría agregar un método a esta clase para cada comando MPD, por ejemplo:

def play(self):
    return self.command("play")

Pero esto parece estar lejos de ser la mejor manera de lograrlo.

¿Fue útil?

Solución

Si no le importa crear una lista de las 91 cadenas que se forman nombres de comando, puedes hacer algo parecido a esta respuesta.Creo que este enfoque tiene muchas ventajas porque implica menos magia.

OTOH, 91 es realmente mucho.Así que aquí tienes una solución automática, que hace uso de una configuración personalizada. __getattr__, que devuelve un contenedor:

from functools import partial
import types

class DummyClient(object):
    def connect(self, *a, **kw): print 'connecting %r %r' % (a, kw)
    def play(self): print 'playing'
    def stop(self): print 'stopping'

class PersistentMPDClient(object):
    def __init__(self, host, port):
        self.host = host
        self.port = port
        self.client = DummyClient()
        self.client.connect(self.host, self.port)

    def __getattr__(self, attr, *args):
        cmd = getattr(self.client, attr, *args)
        if isinstance(cmd, types.MethodType):
            # a method -- wrap
            return lambda *a, **kw: self.command(attr, *a, **kw)
        else:
            # anything else -- return unchanged
            return cmd

    def command(self, cmd, *args, **kwargs):
        command_callable = partial(self.client.__getattribute__(cmd), *args, **kwargs)
        try:
            return command_callable()
        except ConnectionError:
            # Mopidy drops our connection after a while, so reconnect to send the command
            self.client._soc = None
            self.client.connect(self.host, self.port)
            return command_callable()

c = PersistentMPDClient(hostname, port)
c.play()
c.stop()

Mientras escribía esto, noté que @MatToufoutu había publicado una solución similar (aunque hay algunas diferencias).No sé por qué lo borró...Si esa respuesta se recupera, con mucho gusto le daría el crédito que se merece.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top