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)
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 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)
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)
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)
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)
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)
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
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())
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())
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)
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()
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)