예제 #1
0
def send_apple_push_notification(user_id: int, devices: List[DeviceToken],
                                 payload_data: Dict[str, Any]) -> None:
    logging.info("APNs: Sending notification for user %d to %d devices",
                 user_id, len(devices))
    payload = APNsPayload(**modernize_apns_payload(payload_data))
    expiration = int(time.time() + 24 * 3600)
    client = get_apns_client()
    retries_left = APNS_MAX_RETRIES
    for device in devices:
        # TODO obviously this should be made to actually use the async

        def attempt_send() -> Optional[str]:
            stream_id = client.send_notification_async(
                device.token, payload, topic='org.zulip.Zulip',
                expiration=expiration)
            try:
                return client.get_notification_result(stream_id)
            except HTTP20Error as e:
                logging.warning("APNs: HTTP error sending for user %d to device %s: %s",
                                user_id, device.token, e.__class__.__name__)
                return None

        result = attempt_send()
        while result is None and retries_left > 0:
            retries_left -= 1
            result = attempt_send()
        if result is None:
            result = "HTTP error, retries exhausted"

        if result == 'Success':
            logging.info("APNs: Success sending for user %d to device %s",
                         user_id, device.token)
        else:
            logging.warning("APNs: Failed to send for user %d to device %s: %s",
                            user_id, device.token, result)
예제 #2
0
def send_apple_push_notification(user_id: int,
                                 devices: List[DeviceToken],
                                 payload_data: Dict[str, Any],
                                 remote: bool = False) -> None:
    client = get_apns_client()
    if client is None:
        logging.warning(
            "APNs: Dropping a notification because nothing configured.  "
            "Set PUSH_NOTIFICATION_BOUNCER_URL (or APNS_CERT_FILE).")
        return

    if remote:
        DeviceTokenClass = RemotePushDeviceToken
    else:
        DeviceTokenClass = PushDeviceToken

    logging.info("APNs: Sending notification for user %d to %d devices",
                 user_id, len(devices))
    payload = APNsPayload(**modernize_apns_payload(payload_data))
    expiration = int(time.time() + 24 * 3600)
    retries_left = APNS_MAX_RETRIES
    for device in devices:
        # TODO obviously this should be made to actually use the async

        def attempt_send() -> Optional[str]:
            stream_id = client.send_notification_async(device.token,
                                                       payload,
                                                       topic='org.zulip.Zulip',
                                                       expiration=expiration)
            try:
                return client.get_notification_result(stream_id)
            except HTTP20Error as e:
                logging.warning(
                    "APNs: HTTP error sending for user %d to device %s: %s",
                    user_id, device.token, e.__class__.__name__)
                return None

        result = attempt_send()
        while result is None and retries_left > 0:
            retries_left -= 1
            result = attempt_send()
        if result is None:
            result = "HTTP error, retries exhausted"

        if result == 'Success':
            logging.info("APNs: Success sending for user %d to device %s",
                         user_id, device.token)
        elif result in [
                "Unregistered", "BadDeviceToken", "DeviceTokenNotForTopic"
        ]:
            logging.info("APNs: Removing invalid/expired token %s (%s)" %
                         (device.token, result))
            # We remove all entries for this token (There
            # could be multiple for different Zulip servers).
            DeviceTokenClass.objects.filter(
                token=device.token, kind=DeviceTokenClass.APNS).delete()
        else:
            logging.warning(
                "APNs: Failed to send for user %d to device %s: %s", user_id,
                device.token, result)
예제 #3
0
def send_apple_push_notification(user_id, devices, payload_data):
    # type: (int, List[DeviceToken], Dict[str, Any]) -> None
    if not devices:
        return
    logging.info("APNs: Sending notification for user %d to %d devices",
                 user_id, len(devices))
    payload = APNsPayload(**payload_data)
    expiration = int(time.time() + 24 * 3600)
    client = get_apns_client()
    for device in devices:
        # TODO obviously this should be made to actually use the async
        stream_id = client.send_notification_async(device.token,
                                                   payload,
                                                   topic='org.zulip.Zulip',
                                                   expiration=expiration)
        result = client.get_notification_result(stream_id)
        if result == 'Success':
            logging.info("APNs: Success sending for user %d to device %s",
                         user_id, device.token)
        else:
            logging.warn("APNs: Failed to send for user %d to device %s: %s",
                         user_id, device.token, result)
예제 #4
0
def send_apple_push_notification(user_id: int,
                                 devices: List[DeviceToken],
                                 payload_data: Dict[str, Any],
                                 remote: bool = False) -> None:
    # We lazily do the APNS imports as part of optimizing Zulip's base
    # import time; since these are only needed in the push
    # notification queue worker, it's best to only import them in the
    # code that needs them.
    from apns2.payload import Payload as APNsPayload
    from apns2.client import APNsClient
    from hyper.http20.exceptions import HTTP20Error

    client = get_apns_client()  # type: APNsClient
    if client is None:
        logging.warning(
            "APNs: Dropping a notification because nothing configured.  "
            "Set PUSH_NOTIFICATION_BOUNCER_URL (or APNS_CERT_FILE).")
        return

    if remote:
        DeviceTokenClass = RemotePushDeviceToken
    else:
        DeviceTokenClass = PushDeviceToken

    logging.info("APNs: Sending notification for user %d to %d devices",
                 user_id, len(devices))
    payload = APNsPayload(**modernize_apns_payload(payload_data))
    expiration = int(time.time() + 24 * 3600)
    retries_left = APNS_MAX_RETRIES
    for device in devices:
        # TODO obviously this should be made to actually use the async

        def attempt_send() -> Optional[str]:
            stream_id = client.send_notification_async(device.token,
                                                       payload,
                                                       topic='org.zulip.Zulip',
                                                       expiration=expiration)
            try:
                return client.get_notification_result(stream_id)
            except HTTP20Error as e:
                logging.warning(
                    "APNs: HTTP error sending for user %d to device %s: %s",
                    user_id, device.token, e.__class__.__name__)
                return None

        result = attempt_send()
        while result is None and retries_left > 0:
            retries_left -= 1
            result = attempt_send()
        if result is None:
            result = "HTTP error, retries exhausted"

        if result[0] == "Unregistered":
            # For some reason, "Unregistered" result values have a
            # different format, as a tuple of the pair ("Unregistered", 12345132131).
            result = result[0]  # type: ignore # APNS API is inconsistent
        if result == 'Success':
            logging.info("APNs: Success sending for user %d to device %s",
                         user_id, device.token)
        elif result in [
                "Unregistered", "BadDeviceToken", "DeviceTokenNotForTopic"
        ]:
            logging.info("APNs: Removing invalid/expired token %s (%s)" %
                         (device.token, result))
            # We remove all entries for this token (There
            # could be multiple for different Zulip servers).
            DeviceTokenClass.objects.filter(
                token=device.token, kind=DeviceTokenClass.APNS).delete()
        else:
            logging.warning(
                "APNs: Failed to send for user %d to device %s: %s", user_id,
                device.token, result)