def setUp(self): self.started_at = dt_now() cert, key = generate_cert_and_pkey() self.service = APNService.objects.create(name='service', hostname='127.0.0.1', private_key=key, certificate=cert) self.service.PORT = 2195 self.device = Device.objects.create(token=TOKEN, service=self.service)
def set_devices_last_notified_at(self, devices): if isinstance(devices, models.query.QuerySet): devices.update(last_notified_at=dt_now()) else: # Rather than do a save on every object # fetch another queryset and use it to update # the devices in a single query. Device.objects.filter(pk__in=[d.pk for d in devices]).update(last_notified_at=dt_now())
def set_devices_last_notified_at(self, devices): # Rather than do a save on every object, # fetch another queryset and use it to update # the devices in a single query. # Since the devices argument could be a sliced queryset # we can't rely on devices.update() even if devices is # a queryset object. Device.objects.filter(pk__in=[d.pk for d in devices]).update( last_notified_at=dt_now())
def setUp(self): self.started_at = dt_now() cert, key = generate_cert_and_pkey() self.service = APNService.objects.create(name='service', hostname='127.0.0.1', private_key=key, certificate=cert) self.service.PORT = 2195 self.device = Device.objects.create(token=TOKEN, service=self.service) self.IOS_NOTIFICATIONS_PERSIST_NOTIFICATIONS = getattr(settings, 'IOS_NOTIFICATIONS_PERSIST_NOTIFICATIONS', 'NotSpecified')
def _write_message(self, notification, devices, chunk_size): """ Writes the message for the supplied devices to the APN Service SSL socket. """ if not isinstance(notification, Notification): raise TypeError( 'notification should be an instance of ios_notifications.models.Notification' ) if not isinstance(chunk_size, int) or chunk_size < 1: raise ValueError( 'chunk_size must be an integer greater than zero.') payload = notification.payload # Split the devices into manageable chunks. # Chunk sizes being determined by the `chunk_size` arg. device_length = devices.count() if isinstance( devices, models.query.QuerySet) else len(devices) chunks = [ devices[i:i + chunk_size] for i in xrange(0, device_length, chunk_size) ] for index in xrange(len(chunks)): chunk = chunks[index] self._connect() for device in chunk: if not device.is_active: continue try: self.connection.send(self.pack_message(payload, device)) except (OpenSSL.SSL.WantWriteError, socket.error) as e: if isinstance(e, socket.error) and isinstance( e.args, tuple) and e.args[0] != errno.EPIPE: raise e # Unexpected exception, raise it. self._disconnect() i = chunk.index(device) self.set_devices_last_notified_at(chunk[:i]) # Start again from the next device. # We start from the next device since # if the device no longer accepts push notifications from your app # and you send one to it anyways, Apple immediately drops the connection to your APNS socket. # http://stackoverflow.com/a/13332486/1025116 self._write_message(notification, chunk[i + 1:], chunk_size) self._disconnect() self.set_devices_last_notified_at(chunk) if notification.pk or notification.persist: notification.last_sent_at = dt_now() notification.save()
def clean_scheduling_dt(self): """validation""" sch_dt = self.cleaned_data['scheduling_dt'] if not sch_dt: raise ValidationError(_("This field is required")) if sch_dt < dt_now(): raise ValidationError(_("The scheduling date must be in future")) return sch_dt
def setUp(self): self.started_at = dt_now() self.test_server_proc = subprocess.Popen(SSL_SERVER_COMMAND, stdout=subprocess.PIPE) time.sleep(0.5) cert, key = generate_cert_and_pkey() self.service = APNService.objects.create(name='service', hostname='127.0.0.1', private_key=key, certificate=cert) self.service.PORT = 2195 self.device = Device.objects.create(token=TOKEN, service=self.service) self.IOS_NOTIFICATIONS_PERSIST_NOTIFICATIONS = getattr(settings, 'IOS_NOTIFICATIONS_PERSIST_NOTIFICATIONS', 'NotSpecified')
def test_pushing_notification_in_chunks(self): devices = [] for i in xrange(10): token = uuid.uuid1().get_hex() * 2 device = Device.objects.create(token=token, service=self.service) devices.append(device) started_at = dt_now() self.service.push_notification_to_devices(self.notification, devices, chunk_size=2) device_count = len(devices) self.assertEquals(device_count, Device.objects.filter(last_notified_at__gte=started_at).count())
def clean_scheduling_dt(self): """validate datetime""" sch_dt = self.cleaned_data['scheduling_dt'] if not sch_dt: raise ValidationError(ugettext("This field is required")) if sch_dt < dt_now(): raise ValidationError( ugettext("The scheduling date must be in future")) return sch_dt
def setUp(self): self.started_at = dt_now() cert, key = generate_cert_and_pkey() self.service = APNService.objects.create(name='service', hostname='127.0.0.1', private_key=key, certificate=cert) self.service.PORT = 2195 self.device = Device.objects.create(token=TOKEN, service=self.service) self.IOS_NOTIFICATIONS_PERSIST_NOTIFICATIONS = getattr( settings, 'IOS_NOTIFICATIONS_PERSIST_NOTIFICATIONS', 'NotSpecified')
def _write_message(self, notification, devices, chunk_size): """ Writes the message for the supplied devices to the APN Service SSL socket. """ if not isinstance(notification, Notification): raise TypeError('notification should be an instance of ios_notifications.models.Notification') if not isinstance(chunk_size, int) or chunk_size < 1: raise ValueError('chunk_size must be an integer greater than zero.') payload = notification.payload # Split the devices into manageable chunks. # Chunk sizes being determined by the `chunk_size` arg. device_length = devices.count() if isinstance(devices, models.query.QuerySet) else len(devices) chunks = [devices[i:i + chunk_size] for i in xrange(0, device_length, chunk_size)] for index in xrange(len(chunks)): chunk = chunks[index] self._connect() for device in chunk: if not device.is_active: continue try: #self.connection.send(self.pack_message(payload, device)) self.connection.write(self.pack_message(payload, device)) except (OpenSSL.SSL.WantWriteError, socket.error) as e: print 'openssl want write error: {0}'.format(e) if isinstance(e, socket.error) and isinstance(e.args, tuple) and e.args[0] != errno.EPIPE: raise e # Unexpected exception, raise it. self._disconnect() i = chunk.index(device) self.set_devices_last_notified_at(chunk[:i]) # Start again from the next device. # We start from the next device since # if the device no longer accepts push notifications from your app # and you send one to it anyways, Apple immediately drops the connection to your APNS socket. # http://stackoverflow.com/a/13332486/1025116 self._write_message(notification, chunk[i + 1:], chunk_size) self._disconnect() self.set_devices_last_notified_at(chunk) if notification.pk or notification.persist: notification.last_sent_at = dt_now() notification.save()
def test_pushing_notification_in_chunks(self): devices = [] for i in xrange(10): token = uuid.uuid1().get_hex() * 2 device = Device.objects.create(token=token, service=self.service) devices.append(device) started_at = dt_now() self.service.push_notification_to_devices(self.notification, devices, chunk_size=2) device_count = len(devices) self.assertEquals( device_count, Device.objects.filter(last_notified_at__gte=started_at).count())
def test_pushing_notification_in_chunks_with_feedback_service_WantWriteError(self): devices = [] for i in xrange(10): token = uuid.uuid1().get_hex() * 2 device = Device.objects.create(token=token, service=self.service) devices.append(device) started_at = dt_now() endless_success = cycle([None]) with patch('OpenSSL.SSL.Connection') as mocked_Connection: conn = mocked_Connection.return_value conn.send.side_effect = chain([WantWriteError()], endless_success) self.service.push_notification_to_devices(self.notification, devices, chunk_size=2, feedback_service=True) device_count = len(devices) self.assertEquals(device_count, Device.objects.filter(last_notified_at__gte=started_at).count())
def call(self): """ Calls the feedback service and deactivates any devices the feedback service mentions. """ if self.connect(): device_tokens = [] try: while True: data = self.connection.recv(38) # 38 being the length in bytes of the binary format feedback tuple. timestamp, token_length, token = struct.unpack(self.fmt, data) device_token = hexlify(token) device_tokens.append(device_token) except OpenSSL.SSL.ZeroReturnError: # Nothing to receive pass devices = Device.objects.filter(token__in=device_tokens, service=self.apn_service) devices.update(is_active=False, deactivated_at=dt_now()) self.disconnect() return devices.count()
def call(self): """ Calls the feedback service and deactivates any devices the feedback service mentions. """ self._connect() device_tokens = [] try: while True: data = self.connection.recv(38) # 38 being the length in bytes of the binary format feedback tuple. timestamp, token_length, token = struct.unpack(self.fmt, data) device_token = hexlify(token) device_tokens.append(device_token) except OpenSSL.SSL.ZeroReturnError: # Nothing to receive pass finally: self._disconnect() devices = Device.objects.filter(token__in=device_tokens, service=self.apn_service) devices.update(is_active=False, deactivated_at=dt_now()) return devices.count()
def _write_message(self, notification, devices): """ Writes the message for the supplied devices to the APN Service SSL socket. """ if not isinstance(notification, Notification): raise TypeError('notification should be an instance of ios_notifications.models.Notification') if self.connection is None: if not self.connect(): return payload = notification.payload for device in devices: if not device.is_active: continue try: self.connection.send(self.pack_message(payload, device)) except (OpenSSL.SSL.WantWriteError, socket.error) as e: if isinstance(e, socket.error) and isinstance(e.args, tuple) and e.args[0] != errno.EPIPE: raise # Unexpected exception, raise it. self.disconnect() i = devices.index(device) self.set_devices_last_notified_at(devices[:i]) # Start again from the next device. # We start from the next device since # if the device no longer accepts push notifications from your app # and you send one to it anyways, Apple immediately drops the connection to your APNS socket. # http://stackoverflow.com/a/13332486/1025116 return self._write_message(notification, devices[i + 1:]) if self.connect() else None self.set_devices_last_notified_at(devices) if notification.pk or notification.persist: notification.last_sent_at = dt_now() notification.save()
def __init__(self, *args, **kwargs): kwargs['initial'] = {'scheduling_dt': dt_now() + timedelta(minutes=5)} super(NewsletterSchedulingForm, self).__init__(*args, **kwargs)
def set_devices_last_notified_at(self, devices): # Rather than do a save on every object, # fetch another queryset and use it to update # the devices in a single query. # Since the devices argument could be a sliced queryset # we can't rely on devices.update() even if devices is # a queryset object. Device.objects.filter(pk__in=[d.pk for d in devices]).update(last_notified_at=dt_now())
def set_last_sent_time(self, notification): if notification.pk or notification.persist: notification.last_sent_at = dt_now() notification.save() return True return False
def set_devices_last_notified_at(self, devices): # Rather than do a save on every object, # fetch another queryset and use it to update # the devices in a single query. # Since the devices argument could be a sliced queryset # we can't rely on devices.update() even if devices is # a queryset object. try: Device.objects.filter(pk__in=[d.pk for d in devices]).update(last_notified_at=dt_now()) except: # catchall for deadlock; should not occur, but notifications are too important to be allowed to fail\ client = Client(dsn=settings.RAVEN_CONFIG["dsn"]) try: exc_info = sys.exc_info() client.captureException(exc_info) finally: del exc_info