X-Git-Url: http://git.kaliko.me/?p=python-musicpdaio.git;a=blobdiff_plain;f=musicpdasio.py;h=df730e063342fa5bda252f2a1467f0523e8cb3ce;hp=3848ecd0e599f2f2b2b0fba10e432a85c641a362;hb=d6ad3c8276e5068460ab20bc2de5a75e91cc3739;hpb=96e2b25670b663346cc8ad897d3c2705f37fa488 diff --git a/musicpdasio.py b/musicpdasio.py index 3848ecd..df730e0 100644 --- a/musicpdasio.py +++ b/musicpdasio.py @@ -27,6 +27,7 @@ HELLO_PREFIX = "OK MPD " ERROR_PREFIX = "ACK " SUCCESS = "OK" NEXT = "list_OK" +VERSION = '0.0.1b' class MPDError(Exception): @@ -50,7 +51,6 @@ class PendingCommandError(MPDError): class IteratingError(MPDError): pass -loop = asyncio.get_event_loop() class Response: def __init__(self): @@ -59,10 +59,14 @@ class Response: self.err = None def __repr__(self): - return '{0}, {1}… ({2})'.format(self.err, self.resp[:15], self.version) + return 'err:{0}, "{1}…" ({2})'.format( + self.err, + ' '.join(self.resp.split('\n')[:2]), + self.version) class MPDProto(asyncio.Protocol): - def __init__(self, future, payload): + def __init__(self, future, payload, cred): + self.transport = None self.future = future self.payload = payload self.sess = Response() @@ -71,52 +75,69 @@ class MPDProto(asyncio.Protocol): self.transport = transport self.transport.write(bytes('{}\n'.format(self.payload), 'utf-8')) - def data_received(self, data): - rcv = data.decode('utf-8') - if '\n' not in rcv: - self.sess.err = 'Connection lost while reading line' - self.future.set_result(self.sess) - raise ConnectionError("Connection lost while reading line") + def eof_received(self): + self.transport.close() + err = ConnectionError('Connection lost while reading line') + self.future.set_exception(err) - rcv = rcv.strip('\n') + #def connection_lost(self): + # self.eof_received() - if rcv.startswith(HELLO_PREFIX): - self.sess.version = rcv[len(HELLO_PREFIX):] - return - self.transport.close() + def data_received(self, data): + rcv = self._hello(data.decode('utf-8')) - # set the result on the Future so that the main() coroutine can - # resume if rcv.startswith(ERROR_PREFIX): - self.sess.err = rcv[len(ERROR_PREFIX):].strip() - self.future.set_result(self.sess) - return - else: - self.sess.resp = rcv + err = rcv[len(ERROR_PREFIX):].strip() + self.future.set_exception(CommandError(err)) + + self.sess.resp += rcv + if rcv.endswith(SUCCESS+'\n'): + self.transport.close() self.future.set_result(self.sess) -def command(payload): - future = asyncio.Future() - if payload: - cli = MPDProto(future, payload) + def _hello(self, rcv): + """Consume HELLO_PREFIX""" + + if rcv.startswith(HELLO_PREFIX): + self.sess.version = rcv.split('\n')[0][len(HELLO_PREFIX):] + #print('consumed hello prefix: %s' % self.sess.version) + return rcv[rcv.find('\n')+1:] + return rcv + +class MPDClient: + loop = asyncio.get_event_loop() + + def __init__(self, host='localhost', port=6600, cred=None): + self._host = host + self._port = port + self._cred = cred + self._commands = { + 'currentsong', + 'stats', + 'playlistinfo', + } + + def __getattr__(self, attr): + command = attr + wrapper = self._command + if command not in self._commands: + command = command.replace("_", " ") + if command not in self._commands: + raise AttributeError("'%s' object has no attribute '%s'" % + (self.__class__.__name__, attr)) + return lambda *args: wrapper(command, args) + + def _command(self, command, args): + payload = '{} {}'.format(command ,''.join(args)) + future = asyncio.Future() # kick off a task to create the connection to MPD. - asyncio.async(loop.create_connection(lambda: cli, host='192.168.0.20', port=6600)) - else: - future.set_result((None, None, None)) - - # return the future for the main() coroutine to wait on. - return future - - -def main(): - """main""" - import logging - logging.basicConfig(level=logging.DEBUG) - res = yield from command('currentsongt') - if res.err: - raise CommandError(res.err) - print(res) - print(res.resp) - -if __name__ == '__main__': - loop.run_until_complete(main()) + asyncio.async(MPDClient.loop.create_connection( + lambda: MPDProto(future, payload, self._cred), + host=self._host, + port=self._port)) + MPDClient.loop.run_until_complete(future) + #Useless? + #if future.exception(): + # raise future.exception() + # return once completed. + return future.result().resp