def lineReceived(self, line): line = line.decode('utf-8') command_list = self._state and isinstance(self._state[0], list) state_list = self._state[0] if command_list else self._state if line.startswith(HELLO_PREFIX): self.mpd_version = line[len(HELLO_PREFIX):].strip() # default state idle, enter idle if self._default_idle: self.idle().addCallback(self._dispatch_idle_result) elif line.startswith(ERROR_PREFIX): error = line[len(ERROR_PREFIX):].strip() if command_list: state_list[0].errback(CommandError(error)) for state in state_list[1:-1]: state.errback( CommandListError('An earlier command failed.')) state_list[-1].errback(CommandListError(error)) del self._state[0] del self._command_list_results[0] else: state_list.pop(0).errback(CommandError(error)) self._continue_idle() elif line == SUCCESS or (command_list and line == NEXT): state_list.pop(0).callback(self._rcvd_lines[:]) self._rcvd_lines = [] if command_list and line == SUCCESS: del self._state[0] self._continue_idle() else: self._rcvd_lines.append(line)
async def _execute_binary(self, command, args): # Fun fact: By fetching data in lockstep, this is a bit less efficient # than it could be (which would be "after having received the first # chunk, guess that the other chunks are of equal size and request at # several multiples concurrently, ensuring the TCP connection can stay # full), but at the other hand it leaves the command queue empty so # that more time critical commands can be executed right away data = None args = list(args) assert len(args) == 1 args.append(0) final_metadata = None while True: partial_result = BinaryCommandResult() await self.__command_queue.put(partial_result) self._end_idle() self._write_command(command, args) metadata = await partial_result chunk = metadata.pop('binary', None) if final_metadata is None: data = chunk final_metadata = metadata if not data: break try: size = int(final_metadata['size']) except KeyError: size = len(chunk) except ValueError: raise CommandError( "Size data unsuitable for binary transfer") else: if metadata != final_metadata: raise CommandError( "Metadata of binary data changed during transfer") if chunk is None: raise CommandError( "Binary field vanished changed during transfer") data += chunk args[-1] = len(data) if len(data) > size: raise CommandListError("Binary data announced size exceeded") elif len(data) == size: break if data is not None: final_metadata['binary'] = data final_metadata.pop('size', None) return final_metadata
def noidle(self): if not self._idle: raise CommandError('Not in idle state') # delete first pending deferred, idle returns nothing when # noidle gets called self._state.pop(0) self._idle = False return self._execute('noidle', [], self._parse_list)
async def _read_line(self): line = await self.__readline() if not line.endswith("\n"): raise ConnectionError("Connection lost while reading line") line = line.rstrip("\n") if line.startswith(ERROR_PREFIX): error = line[len(ERROR_PREFIX):].strip() raise CommandError(error) if line == SUCCESS: return None return line
def idle(self): if self._idle: raise CommandError('Already in idle state') self._idle = True return self._execute('idle', [], self._parse_list)
def idle(self): if self._idle: raise CommandError("Already in idle state") self._idle = True return self._execute("idle", [], self._parse_list)