Esempio n. 1
0
    def test_feedback(self):
        connection = self.get_connection(session=self.get_session(feedback=5),
                                         address="feedback_production")

        srv = APNs(connection)

        self.assertEqual(len(list(srv.feedback())), 5)
Esempio n. 2
0
 def __init__(self):
     # apns configuration
     session = Session()
     if conf.getboolean('application', 'debug'):
         con = session.new_connection("feedback_sandbox", cert_file=conf.get('apns', 'cert_sandbox'))
     else:
         con = session.new_connection("feedback_production", cert_file=conf.get('apns', 'cert_production'))
     self.srv = APNs(con)
Esempio n. 3
0
    def test_feedback(self):
        if not self._certificate_available():
            # Skip, no certificate available
            return

        connection = self.get_connection(session=self.get_session(),
                                         address="feedback_sandbox")
        srv = APNs(connection)

        self.assertEqual(len(list(srv.feedback())), 0)
Esempio n. 4
0
class APNSFeedbackWorker(object):
    def __init__(self):
        # apns configuration
        session = Session()
        if conf.getboolean('application', 'debug'):
            con = session.new_connection("feedback_sandbox", cert_file=conf.get('apns', 'cert_sandbox'))
        else:
            con = session.new_connection("feedback_production", cert_file=conf.get('apns', 'cert_production'))
        self.srv = APNs(con)

    def start(self):
        try:
            # on any IO failure after successful connection this generator
            # will simply stop iterating. you will pick the rest of the tokens
            # during next feedback session.
            for token, when in self.srv.feedback():
                # every time a devices sends you a token, you should store
                # {token: given_token, last_update: datetime.datetime.now()}
                device = Device.query.filter_by(platform_id=token).first()
                if not device:
                    continue
                if device.updated_at and device.updated_at < when:
                    # the token wasn't updated after the failure has
                    # been reported, so the token is invalid and you should
                    # stop sending messages to it.
                    db.session.delete(device)
                elif not device.updated_at:
                    db.session.delete(device)
            db.session.commit()
        except Exception as ex:
            db.session.rollback()
            logger.exception(ex)
Esempio n. 5
0
    def _apns_push(self, packet):
        envelope = packet.get('envelope')
        to_jid = envelope.get('to')
        to = to_jid.split('@')[0]
        user_info = UserInfo.objects.get(id=to)
        if user_info.device_token:
            logger.info('APNS : %s' % user_info.device_token)
            device_token = user_info.device_token
            payload = packet.get('payload')
            attrs = payload.get('attrs')
            messageType = attrs.get('messageType')
            if 'text' == messageType:
                content = payload.get('content')
            elif 'image' == messageType:
                content = '收到一张图片'
            elif 'geo' == messageType:
                content = '收到一个坐标分享'
            elif 'audio' == messageType:
                content = '收到一条语音'
            elif 'contact' == messageType:  # 联系人接口通知
                action = attrs.get('action')
                if 'add' == action:
                    content = '添加联系人通知'
                elif 'accept' == action:
                    content = '接受好友申请通知'
                elif 'reject' == action:
                    content = '拒绝好友申请通知'
            total = packet.get('total')
            if content and device_token:
                message = Message(tokens=[device_token],
                                  alert=content,
                                  badge=int(total),
                                  content_available=1,
                                  my_extra=15)
                srv = APNs(con)
                res = srv.send(message)

                # Check failures. Check codes in APNs reference docs.
                for token, reason in res.failed.items():
                    code, errmsg = reason
                    logger.info("Device faled: {0}, reason: {1}".format(
                        token, errmsg))

            # Check failures not related to devices.
            for code, errmsg in res.errors:
                logger.error("Error: %s" % errmsg)
Esempio n. 6
0
    def _apns_push(self,packet):
        envelope = packet.get('envelope')
        to_jid = envelope.get('to')
        to = to_jid.split('@')[0]
        user_info = UserInfo.objects.get(id=to)
        if user_info.device_token:
            logger.info('APNS : %s' % user_info.device_token)
            device_token = user_info.device_token
            payload = packet.get('payload')
            attrs = payload.get('attrs')
            messageType = attrs.get('messageType')
            if 'text' == messageType:
                content = payload.get('content')
            elif 'image' == messageType:
                content = '收到一张图片'
            elif 'geo' == messageType:
                content = '收到一个坐标分享'
            elif 'audio' == messageType:
                content = '收到一条语音'
            elif 'contact' == messageType: # 联系人接口通知
                action = attrs.get('action')
                if 'add' == action:
                    content = '添加联系人通知'
                elif 'accept' == action:
                    content = '接受好友申请通知'
                elif 'reject' == action:
                    content = '拒绝好友申请通知'
            total = packet.get('total')
            if content and device_token :
                message = Message(tokens=[device_token], alert=content, badge=int(total), content_available=1, my_extra=15)
                srv = APNs(con)
                res = srv.send(message)

                # Check failures. Check codes in APNs reference docs.
                for token, reason in res.failed.items():
                    code, errmsg = reason
                    logger.info("Device faled: {0}, reason: {1}".format(token, errmsg))

            # Check failures not related to devices.
            for code, errmsg in res.errors:
                logger.error("Error: %s" % errmsg)
Esempio n. 7
0
    def test_send(self):
        # success, retry + include-failed, don't-retry + include-failed
        backend = DummyBackend(push=(None, 1, 3))
        session = Session(pool=backend)

        msg = Message(["0123456789ABCDEF", "FEDCBA9876543210"], alert="my alert", badge=10, content_available=1, my_extra=15)
        push_con = session.get_connection("push_production", cert_string="certificate")
        srv = APNs(push_con)
        res = srv.send(msg)
        self.assertEqual(len(res.failed), 0)
        self.assertEqual(len(res.errors), 0)
        self.assertFalse(res.needs_retry())

        push_con2 = session.get_connection("push_production", cert_string="certificate")
        srv = APNs(push_con2)
        self.assertEqual(session.pool.push_result_pos, 0)
        session.pool.push_result_pos += 1
        res = srv.send(msg)
        self.assertEqual(len(res.failed), 0)
        self.assertEqual(len(res.errors), 1)
        self.assertTrue(res.needs_retry())

        # indeed, we have used the cache
        self.assertEqual(session.pool.new_connections, 1)

        push_con = session.new_connection("push_production", cert_string="certificate")
        srv = APNs(push_con)
        res = srv.send(msg)
        self.assertEqual(len(res.failed), 0)
        self.assertEqual(len(res.errors), 1)
        self.assertFalse(res.needs_retry())

        # indeed, new connection, we haven't used the cache
        self.assertEqual(session.pool.new_connections, 2)
Esempio n. 8
0
def _do_send(tokens, **kwargs):
    message = Message(tokens, **kwargs)
    service = APNs(_get_connection())

    app.logger.info("_DO_SEND TO %s" % (tokens))
    while message:
        response = service.send(message)
        for token, reason in response.failed.items():
            code, errmsg = reason
            # TODO: Invalid tokens, notify admin and disable them
            app.logger.error("APNS: Device: %s - %s - %s" % (token, code, errmsg))

        # Failures not related to devices. TODO: notify admin
        for code, errmsg in response.errors:
            app.logger.error("APNS: Error: %s - %s" % (code, errmsg))

        # Check if there are tokens that can be retried
        if response.needs_retry():
            message = response.retry()
            app.logger.warning("APNS: retrying %s" % (message))
        else:
            message = None

    return response
Esempio n. 9
0
    def test_send(self):
        if not self._certificate_available():
            # Skip, no certificate available
            return

        session = self.get_session()

        # Test with single message
        msg = Message(tokens=[VALID_TOKEN_ONE, VALID_TOKEN_TWO],
                      alert="my alert",
                      badge=10,
                      content_available=1,
                      my_extra=15)

        srv = APNs(self.get_connection(session))
        res = srv.send(msg)

        self.assertEqual(len(res.failed), 1)
        self.assertEqual(len(res.errors), 0)
        self.assertTrue(res.needs_retry())

        # Test with multiple messages
        messages = [
            Message(tokens=[VALID_TOKEN_ONE, VALID_TOKEN_TWO],
                    alert="bar alert",
                    badge=4,
                    my_extra=15),
            Message(tokens=[VALID_TOKEN_THREE],
                    alert="foo alert",
                    badge=0,
                    content_available=1,
                    more_extra=15)
        ]

        srv = APNs(self.get_connection(session))
        res = srv.send(messages)

        self.assertEqual(len(res.failed), 1)
        self.assertEqual(len(res.errors), 0)
        self.assertTrue(res.needs_retry())
Esempio n. 10
0
    def test_send(self):
        # success, retry + include-failed, don't-retry + include-failed
        session = self.get_session(push=(None, 1, 3))

        msg = Message(tokens=[VALID_TOKEN_ONE, VALID_TOKEN_TWO],
                      alert="my alert",
                      badge=10,
                      content_available=1,
                      my_extra=15)

        srv = APNs(self.get_connection(session))
        res = srv.send(msg)

        self.assertEqual(len(res.failed), 0)
        self.assertEqual(len(res.errors), 0)
        self.assertFalse(res.needs_retry())

        srv = APNs(self.get_connection(session))
        self.assertEqual(session.pool.push_result_pos, 0)

        session.pool.push_result_pos += 1
        res = srv.send(msg)

        self.assertEqual(len(res.failed), 0)
        self.assertEqual(len(res.errors), 1)
        self.assertTrue(res.needs_retry())

        # indeed, we have used the cache
        self.assertEqual(session.pool.new_connections, 1)

        srv = APNs(self.get_connection(session))
        res = srv.send(msg)

        self.assertEqual(len(res.failed), 0)
        self.assertEqual(len(res.errors), 1)
        self.assertFalse(res.needs_retry())

        # indeed, new connection, we haven't used the cache
        self.assertEqual(session.pool.new_connections, 2)

        messages = [
            Message(tokens=[VALID_TOKEN_ONE, VALID_TOKEN_TWO],
                    alert="bar alert",
                    badge=4,
                    my_extra=15),
            Message(tokens=[VALID_TOKEN_THREE],
                    alert="foo alert",
                    badge=0,
                    content_available=1,
                    more_extra=15)
        ]

        srv = APNs(self.get_connection(session))
        res = srv.send(messages)
        self.assertEqual(len(res.failed), 0)
        self.assertEqual(len(res.errors), 0)
        self.assertFalse(res.needs_retry())
Esempio n. 11
0
 def _callback(self, ch, method, properties, body):
     """
     send apns notifications
     :param ch:
     :param method:
     :param properties:
     :param body:
     :return:
     """
     self.session.outdate(timedelta(minutes=5))
     if conf.getboolean('application', 'debug'):
         self.apns_con = self.session.get_connection("push_sandbox", cert_file=conf.get('apns', 'cert_sandbox'))
     else:
         self.apns_con = self.session.get_connection("push_production", cert_file=conf.get('apns', 'cert_production'))
     message = loads(body)
     logger.debug('payload: %s' % message)
     badge = None
     sound = 'default'
     content_available = None
     # time to live
     ttl = timedelta(days=5)
     if 'apns' in message['payload']:
         if 'badge' in message['payload']['apns']:
             badge = message['payload']['apns']['badge']
         if 'sound' in message['payload']['apns']:
             sound = message['payload']['apns']['sound']
         if 'content_available' in message['payload']['apns']:
             content_available = message['payload']['apns']['content_available']
     if 'ttl' in message['payload']:
         ttl = timedelta(seconds=message['payload']['ttl'])
     message = Message(message['devices'],
                       alert=message['payload']['alert'],
                       badge=badge,
                       sound=sound,
                       content_available=content_available,
                       expiry=ttl,
                       extra=message['payload']['data'] if 'data' in message['payload'] else None)
     try:
         srv = APNs(self.apns_con)
         response = srv.send(message)
         logger.debug('apns response: %s' % response)
     except Exception as ex:
         ch.basic_ack(delivery_tag=method.delivery_tag)
         logger.exception(ex)
         return
     # Check failures. Check codes in APNs reference docs.
     for token, reason in response.failed.items():
         code, errmsg = reason
         # according to APNs protocol the token reported here
         # is garbage (invalid or empty), stop using and remove it.
         logger.info('delivery failure apns_token: %s, reason: %s' % (token, errmsg))
         device_obj = Device.query.filter_by(platform_id=token).first()
         if device_obj:
             db.session.delete(device_obj)
     try:
         db.session.commit()
     except Exception as ex:
         db.session.rollback()
         logger.exception(ex)
     # Check failures not related to devices.
     for code, errmsg in response.errors:
         logger.error(errmsg)
     # Check if there are tokens that can be retried
     if response.needs_retry():
         # repeat with retry_message or reschedule your task
         srv.send(response.retry())
     ch.basic_ack(delivery_tag=method.delivery_tag)
Esempio n. 12
0
def send_apns_message(device, app, message_type, data=None):
    """
    Send an Apple Push Notification message.
    """
    token_list = [device.token]
    unique_key = device.token

    if message_type == TYPE_CALL:
        unique_key = data['unique_key']
        message = Message(token_list,
                          payload=get_call_push_payload(
                              unique_key, data['phonenumber'],
                              data['caller_id']))
    elif message_type == TYPE_MESSAGE:
        message = Message(token_list,
                          payload=get_message_push_payload(data['message']))
    else:
        logger.warning('{0} | TRYING TO SENT MESSAGE OF UNKNOWN TYPE: {1}',
                       unique_key, message_type)

    session = Session()

    push_mode = settings.APNS_PRODUCTION
    if device.sandbox:
        # Sandbox push mode.
        push_mode = settings.APNS_SANDBOX

    full_cert_path = os.path.join(settings.CERT_DIR, app.push_key)

    con = session.get_connection(push_mode, cert_file=full_cert_path)
    srv = APNs(con)

    try:
        logger.info(
            '{0} | Sending APNS \'{1}\' message at time:{2} to {3} Data:{4}'.
            format(
                unique_key, message_type,
                datetime.datetime.fromtimestamp(
                    time()).strftime('%H:%M:%S.%f'), device.token, data))
        res = srv.send(message)

    except Exception:
        logger.exception('{0} | Error sending APNS message'.format(
            unique_key, ))

    else:
        # Check failures. Check codes in APNs reference docs.
        for token, reason in res.failed.items():
            code, errmsg = reason
            # According to APNs protocol the token reported here
            # is garbage (invalid or empty), stop using and remove it.
            logger.warning(
                '{0} | Sending APNS message failed for device: {1}, reason: {2}'
                .format(unique_key, token, errmsg))

        # Check failures not related to devices.
        for code, errmsg in res.errors:
            logger.warning('{0} | Error sending APNS message. \'{1}\''.format(
                unique_key, errmsg))

        # Check if there are tokens that can be retried.
        if res.needs_retry():
            logger.info('{0} | Could not sent APNS message, retrying...')
            # Repeat with retry_message or reschedule your task.
            res.retry()
Esempio n. 13
0
 def test_feedback(self):
     backend = DummyBackend(feedback=5)
     session = Session(pool=backend)
     feed_con = session.new_connection("feedback_production", cert_string="certificate")
     srv = APNs(feed_con)
     self.assertEqual(len(list(srv.feedback())), 5)