def _parse(self, stream, context, path): b = byte2int(stream_read(stream, 1, path)) extrabytes, mask = [ # lookup table [0, 0xff], # (0b0xxxxxxx) [0, 0xff], # (0b0xxxxxxx) [1, 0x7f], # 0x80 (0b10xxxxxx) [2, 0x00] # 0xC0 (0b11xxxxxx) ][b >> 6] num = b & mask for _ in range(extrabytes): num = (num << 8) + byte2int(stream_read(stream, 1, path)) return num
def query_blob(self, player_number, slot, item_id, request_type, location=8): sock = self.getSocket(player_number) slot_id = byte2int(packets.PlayerSlot.build(slot)) query = { "transaction_id": self.getTransactionId(player_number), "type": request_type, "args": [ {"type": "int32", "value": self.own_player_number<<24 | location<<16 | slot_id<<8 | 1}, {"type": "int32", "value": item_id} ] } # request-specific argument agumentations if request_type == "waveform_request": query["args"].append({"type": "int32", "value": 0}) elif request_type == "preview_waveform_request": query["args"].insert(1, {"type": "int32", "value": 4}) query["args"].append({"type": "int32", "value": 0}) logging.debug("DBClient: {} query {}".format(request_type, query)) data = packets.DBMessage.build(query) self.socksnd(sock, data) try: reply = self.receive_dbmessage(sock) except (RangeError, FieldError, MappingError, KeyError, TypeError) as e: logging.error("DBClient: %s query parse error: %s", request_type, str(e)) return None if reply is None: return None if reply["type"] == "invalid_request" or len(reply["args"])<3 or reply["args"][2]["value"] == 0: logging.error("DBClient: %s blob query failed on player %d (got %s)", query["type"], player_number, reply["type"]) return None blob = reply["args"][3]["value"] logging.debug("DBClient: got %d bytes of blob data", len(blob)) return blob
def _parse(self, stream, context, path): b = byte2int(stream_read(stream, 1, path)) extrabytes, mask = [ [0, 0xff], [0, 0xff], [0, 0xff], [0, 0xff], # (0b0..xxxxx) [1, 0x7f], [1, 0x7f], # 0x80 (0b10.xxxxx) [3, 0x3f], # 0xC0 (0b110xxxxx) [4, 0x00] # 0xE0 (0b111xxxxx) ][b >> 5] num = b & mask for _ in range(extrabytes): num = (num << 8) + byte2int(stream_read(stream, 1, path)) return num
def _parse(self, stream, context, path): acc = [] while True: b = byte2int(stream_read(stream, 1)) acc.append(b & 0b01111111) if not b & 0b10000000: break num = 0 for b in acc: num = (num << 7) | b return num
def query_link_info(self, player_number, slot): cl = self.prodj.cl.getClient(player_number) if cl is None: logging.warning("Failed to get player %d", player_number) return slot_id = byte2int(packets.PlayerSlot.build(slot)) cmd = { "type": "link_query", "model": self.model, "player_number": self.player_number, "source_ip": self.ip_addr, "remote_player_number": player_number, "slot": slot_id } data = packets.StatusPacket.build(cmd) logging.debug("query link info to %s struct %s", cl.ip_addr, str(cmd)) self.prodj.status_sock.sendto(data, (cl.ip_addr, self.prodj.status_port))
def _parse(self, stream, context, path): result = 0 sign = 1 i = 0 depth = 0 while True: length = self.lengths[i] bits = byte2int(stream_read(stream, 1, path)) mask = self._get_data_mask(length) data = bits & mask more = self._get_more_bit(length) & bits if (i == 0) and (self.negative_bit & bits): sign = -1 result |= data << depth if not more: break i += 1 depth += length return sign * result
def command_load_track(self, player_number, load_player_number, load_slot, load_track_id): cl = self.prodj.cl.getClient(player_number) if cl is None: logging.warning("Failed to get player %d", player_number) return load_slot_id = byte2int(packets.PlayerSlot.build(load_slot)) cmd = { "type": "load_cmd", "model": self.model, "player_number": self. player_number, # our player number -> we receive confirmation packet "player_number2": self. player_number, # our player number -> we receive confirmation packet "load_player_number": load_player_number, "load_slot": load_slot_id, "load_track_id": load_track_id } data = packets.StatusPacket.build(cmd) logging.debug("send load packet to %s struct %s", cl.ip_addr, str(cmd)) self.prodj.status_sock.sendto(data, (cl.ip_addr, self.prodj.status_port))
def query_list(self, player_number, slot, sort_mode, id_list, request_type): sock = self.getSocket(player_number) slot_id = byte2int( packets.PlayerSlot.build(slot)) if slot is not None else 0 if sort_mode is None: sort_id = 0 # 0 for root_menu, playlist folders else: if sort_mode not in sort_types: logging.warning("DBClient: unknown sort mode %s", sort_mode) return None sort_id = sort_types[sort_mode] query = { "transaction_id": self.getTransactionId(player_number), "type": request_type, "args": [{ "type": "int32", "value": self.own_player_number << 24 | 1 << 16 | slot_id << 8 | 1 }] } # request-specific argument agumentations if request_type == "root_menu_request": query["args"].append({"type": "int32", "value": 0}) query["args"].append({"type": "int32", "value": 0xffffff}) elif request_type in [ "metadata_request", "track_data_request", "track_info_request" ]: query["args"].append({"type": "int32", "value": id_list[0]}) elif request_type == "playlist_request": query["args"].append({"type": "int32", "value": sort_id}) query["args"].append({ "type": "int32", "value": id_list[1] if id_list[1] > 0 else id_list[0] }) query["args"].append({ "type": "int32", "value": 0 if id_list[1] > 0 else 1 }) # 1 -> get folder, 0 -> get playlist else: # for any (non-playlist) "*_by_*_request" query["args"].append({"type": "int32", "value": sort_id}) for item_id in id_list: if item_id == 0: # we use id 0 for "ALL", dbserver expects all bits set item_id = 0xffffffff query["args"].append({"type": "int32", "value": item_id}) data = packets.DBMessage.build(query) logging.debug("DBClient: query_list request: {}".format(query)) self.socksnd(sock, data) try: reply = self.receive_dbmessage(sock) except (RangeError, MappingError, KeyError) as e: logging.error( "DBClient: parsing %s query failed on player %d failed: %s", query["type"], player_number, str(e)) return None if reply is None or reply["type"] != "success": logging.error("DBClient: %s failed on player %d (got %s)", query["type"], player_number, "NONE" if reply is None else reply["type"]) return None entry_count = reply["args"][1]["value"] if entry_count == 0: logging.warning("DBClient: %s empty (0 entries)", request_type) return [] logging.debug("DBClient: query_list %s: %d entries available", request_type, entry_count) # i could successfully receive hundreds of entries at once on xdj 1000 # thus i do not fragment render requests here query = { "transaction_id": self.getTransactionId(player_number), "type": "render", "args": [ { "type": "int32", "value": self.own_player_number << 24 | 1 << 16 | slot_id << 8 | 1 }, { "type": "int32", "value": 0 }, # entry offset { "type": "int32", "value": entry_count }, # entry count { "type": "int32", "value": 0 }, { "type": "int32", "value": entry_count }, # entry count { "type": "int32", "value": 0 } ] } data = packets.DBMessage.build(query) logging.debug("DBClient: render query {}".format(query)) self.socksnd(sock, data) parse_errors = 0 receive_timeouts = 0 data = b"" while parse_errors < self.parse_error_count and receive_timeouts < self.receive_timeout_count: new_data = sockrcv(sock, 4096, 1) if len(new_data) == 0: receive_timeouts += 1 continue data += new_data try: reply = packets.ManyDBMessages.parse(data) except (RangeError, FieldError, MappingError, KeyError, TypeError) as e: logging.debug( "DBClient: failed to parse %s render reply (%d bytes), trying to receive more", request_type, len(data)) parse_errors += 1 else: if reply[-1]["type"] != "menu_footer": logging.debug( "DBClient: %s rendering without menu_footer @ %d bytes, trying to receive more", request_type, len(data)) parse_errors += 1 else: break if parse_errors >= self.parse_error_count or receive_timeouts >= self.receive_timeout_count: raise dataprovider.FatalQueryError( "DBClient: Failed to receive {} render reply after {} timeouts, {} parse errors" .format(request_type, receive_timeouts, parse_errors)) # basically, parse_metadata returns a single dict whereas parse_list returns a list of dicts if request_type in [ "metadata_request", "mount_info_request", "track_info_request" ]: parsed = self.parse_metadata(reply) else: parsed = self.parse_list(reply) return parsed