<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def login_or_register( client: GMatrixClient, signer: Signer, prev_user_id: str = None, prev_access_token: str = None, ) -> User: """Login to a Raiden matrix server with password and displayname proof-of-keys - Username is in the format: 0x<eth_address>(.<suffix>)?, where the suffix is not required, but a deterministic (per-account) random 8-hex string to prevent DoS by other users registering our address - Password is the signature of the server hostname, verified by the server to prevent account creation spam - Displayname currently is the signature of the whole user_id (including homeserver), to be verified by other peers. May include in the future other metadata such as protocol version Params: client: GMatrixClient instance configured with desired homeserver signer: raiden.utils.signer.Signer instance for signing password and displayname prev_user_id: (optional) previous persisted client.user_id. Must match signer's account prev_access_token: (optional) previous persistend client.access_token for prev_user_id Returns: Own matrix_client.User """

    server_url = client.api.base_url
    server_name = urlparse(server_url).netloc

    base_username = to_normalized_address(signer.address)
    _match_user = re.match(
        f'^@{re.escape(base_username)}.*:{re.escape(server_name)}$',
        prev_user_id or '',
    )
    if _match_user:  # same user as before
        log.debug('Trying previous user login', user_id=prev_user_id)
        client.set_access_token(user_id=prev_user_id, token=prev_access_token)

        try:
            client.api.get_devices()
        except MatrixRequestError as ex:
            log.debug(
                'Couldn\'t use previous login credentials, discarding',
                prev_user_id=prev_user_id,
                _exception=ex,
            )
        else:
            prev_sync_limit = client.set_sync_limit(0)
            client._sync()  # initial_sync
            client.set_sync_limit(prev_sync_limit)
            log.debug('Success. Valid previous credentials', user_id=prev_user_id)
            return client.get_user(client.user_id)
    elif prev_user_id:
        log.debug(
            'Different server or account, discarding',
            prev_user_id=prev_user_id,
            current_address=base_username,
            current_server=server_name,
        )

    # password is signed server address
    password = encode_hex(signer.sign(server_name.encode()))
    rand = None
    # try login and register on first 5 possible accounts
    for i in range(JOIN_RETRIES):
        username = base_username
        if i:
            if not rand:
                rand = Random()  # deterministic, random secret for username suffixes
                # initialize rand for seed (which requires a signature) only if/when needed
                rand.seed(int.from_bytes(signer.sign(b'seed')[-32:], 'big'))
            username = f'{username}.{rand.randint(0, 0xffffffff):08x}'

        try:
            client.login(username, password, sync=False)
            prev_sync_limit = client.set_sync_limit(0)
            client._sync()  # when logging, do initial_sync with limit=0
            client.set_sync_limit(prev_sync_limit)
            log.debug(
                'Login',
                homeserver=server_name,
                server_url=server_url,
                username=username,
            )
            break
        except MatrixRequestError as ex:
            if ex.code != 403:
                raise
            log.debug(
                'Could not login. Trying register',
                homeserver=server_name,
                server_url=server_url,
                username=username,
            )
            try:
                client.register_with_password(username, password)
                log.debug(
                    'Register',
                    homeserver=server_name,
                    server_url=server_url,
                    username=username,
                )
                break
            except MatrixRequestError as ex:
                if ex.code != 400:
                    raise
                log.debug('Username taken. Continuing')
                continue
    else:
        raise ValueError('Could not register or login!')

    name = encode_hex(signer.sign(client.user_id.encode()))
    user = client.get_user(client.user_id)
    user.set_display_name(name)
    return user