import json import binascii from google.protobuf import json_format # pylint: disable=no-name-in-module from lbrynet.schema.error import DecodeError, InvalidAddress from lbrynet.schema.legacy.migrate import migrate as schema_migrator from lbrynet.schema.claim import ClaimDict def migrate_json_claim_value(decoded_json): try: if 'fee' in decoded_json: old_fee = decoded_json['fee'] if not old_fee[list(old_fee.keys())[0]]['amount']: del decoded_json['fee'] return migrate_json_claim_value(decoded_json) except (TypeError, AttributeError, InvalidAddress): raise DecodeError("Failed to decode claim") try: pb_migrated = schema_migrator(decoded_json) return pb_migrated except json_format.ParseError as parse_error: raise DecodeError("Failed to parse protobuf: %s" % parse_error) except Exception as err: raise DecodeError("Failed to migrate claim: %s" % err) def smart_decode(claim_value): """ Decode a claim value Try decoding claim protobuf, if this fails try decoding json and migrating it. If unable to decode or migrate, raise DecodeError """ # if already decoded, return if isinstance(claim_value, ClaimDict): return claim_value elif isinstance(claim_value, dict): return ClaimDict.load_dict(claim_value) try: claim_value = binascii.unhexlify(claim_value) except (TypeError, ValueError): pass if claim_value[0] in ['{', ord('{')]: try: if isinstance(claim_value, bytes): claim_value = claim_value.decode() decoded_json = json.loads(claim_value) return migrate_json_claim_value(decoded_json) except (ValueError, TypeError): pass try: if isinstance(claim_value, str): claim_value = claim_value.encode() return ClaimDict.deserialize(claim_value) except (DecodeError, InvalidAddress, KeyError, TypeError): raise DecodeError(claim_value)