pr0ger / pyapns2 Goto Github PK
View Code? Open in Web Editor NEWPython library for interacting with the Apple Push Notification service (APNs) via HTTP/2 protocol
License: MIT License
Python library for interacting with the Apple Push Notification service (APNs) via HTTP/2 protocol
License: MIT License
An error occurs if the heartbeat_period parameter is set:
File "/home/web/.py3env/lib/python3.6/site-packages/apns2-0.4.1-py3.6.egg/apns2/client.py", line 179, in send_notification_batch
result = self.get_notification_result(pending_stream.stream_id)
File "/home/web/.py3env/lib/python3.6/site-packages/apns2-0.4.1-py3.6.egg/apns2/client.py", line 122, in get_notification_result
with self._connection.get_response(stream_id) as response:
File "/home/web/.py3env/lib/python3.6/site-packages/hyper/http20/connection.py", line 312, in get_response
return HTTP20Response(stream.getheaders(), stream)
File "/home/web/.py3env/lib/python3.6/site-packages/hyper/http20/stream.py", line 230, in getheaders
self._recv_cb(stream_id=self.stream_id)
File "/home/web/.py3env/lib/python3.6/site-packages/hyper/http20/connection.py", line 771, in _recv_cb
self._single_read()
File "/home/web/.py3env/lib/python3.6/site-packages/hyper/http20/connection.py", line 665, in _single_read
self._sock.fill()
File "/home/web/.py3env/lib/python3.6/site-packages/hyper/common/bufsocket.py", line 167, in fill
count = self._sck.recv_into(self._buffer_view[self._buffer_end:])
File "/home/web/.py3env/lib/python3.6/site-packages/gevent/_ssl3.py", line 503, in recv_into
return self.read(nbytes, buffer)
File "/home/web/.py3env/lib/python3.6/site-packages/gevent/_ssl3.py", line 332, in read
self._wait(self._read_event, timeout_exc=_SSLErrorReadTimeout)
File "src/gevent/_hub_primitives.py", line 265, in gevent.__hub_primitives.wait_on_socket
File "src/gevent/_hub_primitives.py", line 266, in gevent.__hub_primitives.wait_on_socket
File "src/gevent/_hub_primitives.py", line 252, in gevent.__hub_primitives._primitive_wait
File "src/gevent/_hub_primitives.py", line 46, in gevent.__hub_primitives.WaitOperationsGreenlet.wait
File "src/gevent/_hub_primitives.py", line 46, in gevent.__hub_primitives.WaitOperationsGreenlet.wait
File "src/gevent/_hub_primitives.py", line 55, in gevent.__hub_primitives.WaitOperationsGreenlet.wait
File "src/gevent/_waiter.py", line 151, in gevent.__waiter.Waiter.get
File "src/gevent/_greenlet_primitives.py", line 59, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 59, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/_greenlet_primitives.py", line 63, in gevent.__greenlet_primitives.SwitchOutGreenletWithLoop.switch
File "src/gevent/__greenlet_primitives.pxd", line 35, in gevent.__greenlet_primitives._greenlet_switch
greenlet.error: cannot switch to a different thread
n_notifications = [n] * len(n_push_tokens)
pyapns.notify(‘app', n_push_tokens, n_notifications)
Referring to apple's spec here:
If the value in the :status header is 410, the value of this key is the last time at which APNs confirmed that the device token was no longer valid for the topic.
Stop pushing notifications until the device registers a token with a later timestamp with your provider.
If you add the timestamp value to the exception then it would be possible to check the timestamp of when the push token was last provided by the client and whether or not it should in fact be removed.
Hi!
It seems that apple will disconnect the socket if the apns client does not send any message to the apns server for a while(maybe several hours),and a ConnectionResetError
would be raised from the underlying hyper
package when you send message using the remotely closed socket.
To handle this, I just hack it like the code below, which I don't think is an elegant way.
apns = APNsClient()
try:
apns.send_notification(device_token, payload, topic=APNS_TOPIC)
except hyper.common.exceptions.ConnectionResetError:
global apns
## just init a new apns client instance
apns = APNsClient()
apns.send_notification(device_token, payload, topic=APNS_TOPIC)
There may exist a good way to solve the connection reset problem just in the pyapns2
package,
any ideas?
Thanks.
Can you offer any help on this? I thought it was potentially because I was sending unicode (see urllib3/urllib3#855) but I see you are doing some unicode conversion and I made sure that my collapse IDs and tokens aren't unicode.
Any help will be gratefully received as this is causing issue when I try and send push notifications to a lot of users at the same time.
We have been using this client to send notifications through APNS to iPhones.
Here is the client and the send_notification function
apns_client = APNsClient(settings.APNS_CERT_PATH, use_sandbox=True, use_alternative_port=False)
results = apns_client.send_notification_batch(notifications, APPID_IOS, expiration=ttl, collapse_id=apns_collapse_id)
We have a specific requirement where we require the notification to be expired 45 seconds post sending. However, the expiration time as such is not honoured. We ran a test scenario where we sent a notification to a device while it was offline, and we brought it up online after 55 seconds. The notification still reached, even though the expiration time was set at 45 seconds.
Along with that, we have also been experimenting with notifications with apns-expiration = 0. According to Apple's documentation
If the value is 0, APNs treats the notification as if it expires immediately and does not store the notification or attempt to redeliver it.
However, when we sent out a notification to a device which we brought online 10 seconds after sending it out, the notification still reached, even though expiration was set to zero.
Is there something we are missing? Or is it something on the side of APNS? Any help would be greatly appreciated.
Thanks in advance.
Python Version - 3.5.1
Thank you for the great work, you saved me a ton of time! I have encountered an issue and sometimes I randomly get a Stream forcefully closed
exception. This is definitely not because of a certificate issue as it works the majority of times. Here's the debug trace leading to the exception:
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] HPACK encoding <generator object inner at 0x7f14f75b01f0>
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Adding (':method', 'POST') to the header table
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Encoding 3 with 7 bits
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Adding (':scheme', 'https') to the header table
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Encoding 7 with 7 bits
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Adding (':authority', 'api.development.push.apple.com') to the header table
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Encoding 64 with 7 bits
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Adding (':path', '/3/device/************************* [HIDDEN] ***************************') to the header table
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Encoding 63 with 7 bits
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Adding ('apns-topic', 'com.organization.Application') to the header table
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Encoding 62 with 7 bits
[2018-07-09 01:00:43 PM] [hpack.hpack ] [DEBUG] Encoded header block to �����
[2018-07-09 01:00:43 PM] [hyper.http20.connection ] [DEBUG] recv for stream 3 with set([]) already present
[2018-07-09 01:00:43 PM] [hyper.http20.connection ] [DEBUG] Close stream 3
[2018-07-09 01:00:43 PM] [hyper.http20.connection ] [DEBUG] recv for stream 3 with set([]) already present
[2018-07-09 01:00:43 PM] [root ] [ERROR] Stream forcefully closed
Any ideas where the problem might be?
I am frequently getting
TooManyStreamsError Exception occurred. Max outbound streams is 1000, 1000 open
I am using apns2==0.5.0
apns_response = apns.get_notification_result(stream_id)
File "/usr/local/lib/python3.6/site-packages/apns2/client.py", line 116, in get_notification_result
with self._connection.get_response(stream_id) as response:
File "/usr/local/lib/python3.6/site-packages/hyper/http20/connection.py", line 311, in get_response
stream = self._get_stream(stream_id)
File "/usr/local/lib/python3.6/site-packages/hyper/http20/connection.py", line 289, in _get_stream
raise StreamResetError("Stream forcefully closed")
hyper.http20.exceptions.StreamResetError: Stream forcefully closed"
I am trying to send voip notifications so I need to change the server and port to use gateway.sandbox.push.apple.com but when I do so I just get loads of errors I can't figure out if http2 is problem.
When I try to execute the script linking the library I get a syntax error:
Traceback (most recent call last):
File "remotenotifications.py", line 1, in
from apns2.client import APNsClient
File "/var/www/html/iPhone/tags/apns2/client.py", line 50
credentials: Union[Credentials, str],
^
As I can see in your APNsClient constructor you dont have option to add cerf. password while in load_cer_chain method you have an option to add one. I will add pw option in constructor.
Hi, I tried to run the sample code that is put in the readme file of the project but I faced this error:
Traceback (most recent call last):
File "//anaconda/envs/lyan/lib/python3.5/code.py", line 91, in runcode
exec(code, self.locals)
File "<console>", line 1, in <module>
File "//anaconda/envs/lyan/lib/python3.5/site-packages/apns2/client.py", line 53, in send_notification
stream_id = self.send_notification_async(token_hex, notification, topic, priority, expiration, collapse_id)
File "//anaconda/envs/lyan/lib/python3.5/site-packages/apns2/client.py", line 78, in send_notification_async
stream_id = self._connection.request('POST', url, json_payload, headers)
File "//anaconda/envs/lyan/lib/python3.5/site-packages/hyper/http20/connection.py", line 281, in request
self.endheaders(message_body=body, final=True, stream_id=stream_id)
File "//anaconda/envs/lyan/lib/python3.5/site-packages/hyper/http20/connection.py", line 546, in endheaders
stream = self._get_stream(stream_id)
File "//anaconda/envs/lyan/lib/python3.5/site-packages/hyper/http20/connection.py", line 289, in _get_stream
raise StreamResetError("Stream forcefully closed")
hyper.http20.exceptions.StreamResetError: Stream forcefully closed
Any idea for solving this problem?
Thanks
This would make supporting multiple applications easier.
If it's alright, I'd like to add this. I don't know if it's overarchitecting, but I was thinking of replacing the cert_file parameter in APNsClient's init with a new Credentials class instance. There would be two subclasses: the CertificateCredentials and TokenCredentials. (Since tokens are meant to be reused (currently, for up to an hour), clients could come and go, as long as someone is holding on to the credentials instance.) Both classes would implement get_connection and get_authentication_header methods.
We could keep the old API too, and create the credential class if that parameter is a string:
def __init__(self, credentials, use_sandbox=False,...
...
if isinstance(credentials, str):
self.__credentials = CertificateCredentials(credentials)
else:
self.__credentials = credentials
without phrase parameter supporting?
Why https://libraries.io/pypi/apns2 install block told us to pip install apns2==0.3.0
in parallel to clone from repo and use it.
This two repositories are different.
For example apns2/client.py
So my questions are.
Could I use PyAPNs2 this repo) in prodaction?
And why this happens?
Thanks.
Sorry for noob Q.
ok, that was naming collision.
Actual app have a name apns2-client
.
Hello,
first of all many thanks for the great package!
I just tried the code snippet that's shown in the README
, but whenever I execute it, I get the following error:
client.send_notification(token, payload)
File "/usr/local/lib/python3.4/dist-packages/apns2/client.py", line 38, in send_notification
stream_id = self.__connection.request('POST', url, json_payload, headers)
File "/usr/local/lib/python3.4/dist-packages/hyper/http20/connection.py", line 281, in request
self.endheaders(message_body=body, final=True, stream_id=stream_id)
File "/usr/local/lib/python3.4/dist-packages/hyper/http20/connection.py", line 546, in endheaders
stream = self._get_stream(stream_id)
File "/usr/local/lib/python3.4/dist-packages/hyper/http20/connection.py", line 289, in _get_stream
raise StreamResetError("Stream forcefully closed")
hyper.http20.exceptions.StreamResetError: Stream forcefully closed
Does anyone have an idea what I am doing wrong here?
Many thanks!
Have a nice day,
Bernhard
Is there a way to set a timeout for the APNS response? I couldn't find anything in the doc to confirm this.
I've just checked our dependencies, and the oldest 2 dependencies are transient from this project.
Specifically, it appears that hyper
has been out of development since 2016, and superseded by h2
, for which the most recent release was in the last 2 weeks.
Could this project be ported to a recent version of h2
?
File "/opt/pushapp/lib/python2.7/site-packages/apns2/client.py", line 53, in send_notification stream_id = self.send_notification_async(token_hex, notification, topic, priority, expiration, collapse_id)
File "/opt/pushapp/lib/python2.7/site-packages/apns2/client.py", line 78, in send_notification_async stream_id = self._connection.request('POST', url, json_payload, headers)
File "/opt/pushapp/lib/python2.7/site-packages/hyper/http20/connection.py", line 281, in request self.endheaders(message_body=body, final=True, stream_id=stream_id)
File "/opt/pushapp/lib/python2.7/site-packages/hyper/http20/connection.py", line 555, in endheaders stream.send_headers(headers_only)
File "/opt/pushapp/lib/python2.7/site-packages/hyper/http20/stream.py", line 99, in send_headers self._send_outstanding_data()
File "/opt/pushapp/lib/python2.7/site-packages/hyper/http20/connection.py", line 466, in _send_outstanding_data self._send_cb(data, tolerate_peer_gone=tolerate_peer_gone)
File "/opt/pushapp/lib/python2.7/site-packages/hyper/http20/connection.py", line 622, in _send_cb self._sock.sendall(data)
File "/opt/pushapp/lib/python2.7/site-packages/hyper/ssl_compat.py", line 168, in sendall return self._safe_ssl_call(False, self._conn.sendall, data, flags)
File "/opt/pushapp/lib/python2.7/site-packages/hyper/ssl_compat.py", line 130, in _safe_ssl_call raise socket.error(e.args[0])error: [('SSL routines', 'ssl3_write_pending', 'bad write retry')]
On Ubuntu 16.04, which has Python 3.5.2, apns2.client
fails to import, because typing.Deque
was not added until Python 3.5.4.
>>> import apns2.client
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.5/dist-packages/apns2/client.py", line 9, in <module>
from typing import Deque, Dict, Iterable, Optional, Tuple, Type, Union
ImportError: cannot import name 'Deque'
I'm getting InvalidPushType when attempting to send a VOIP push with apns-push-type specified.
Hi, regarding the heartbeat_period
method of keeping a connection from breaking during periods of inactivity, is there a recommended default value?
@arthur-a in your PR you mentioned that "when connection is not used for several minutes" the connection may break. In your example you use 10 seconds. I imagine it may be safe to use 60s or 120s. What do you recommend?
Also, @Pr0Ger, would you accept a PR to enable the heartbeat_period by default, or a PR to update the README about its usage?
how can i add custom keys to payload?
I've been trying to generate the key.pem
certificate needed to create the connection to Apple's servers, but I haven't been able to get it working. Could you please provide the steps you used to generate a working file?
Using these instructions:
https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AddingCapabilities/AddingCapabilities.html#//apple_ref/doc/uid/TP40012582-CH26-SW11
I've been able to export either a .p12
file or a .cer
file when selecting both the Apple Push Services
certificate and the private key under Keychain Assistant > My Certificates.
Thanks!
What might be the possible reasons for this error? I'm attempting to catch the exception at the end of the 'send_notification' method.
I'm trying to establish this functionality, but failing miserably in certificate initialisation phase:
I have generated a "VoIP Services" certificate.
Downloaded it comes in .cer format. I convert it to .pem using OpenSSL:
openssl x509 -inform der -in ios.cer -out ios.pem
Whichever of these two certificates I try to use:
client = APNsClient(os.path.join(settings.BASE_DIR, 'ScantronServer' ,'ios.cer'),
use_sandbox=False, use_alternative_port=False)
I get a similar error:
ssl.SSLError: [SSL] PEM lib (_ssl.c:3288) --> for .cer
ssl.SSLError: [SSL] PEM lib (_ssl.c:3309) --> for .pem
The way I see it after much debugging is that the issue is in library trying to validate the entire certificate chain, which it does not have.
Am I generating a wrong certificate type / converting it incorrectly?
When trying to connect to both development and production APNS HTTP/2 servers on the alternative port (2197), the connection is reset upon creation. When using the regular 443 port, the connection is established.
Expected behavior: The connection should be successfully established using both ports, 443 and 2197.
Cause: If a port different than 443 is used, then the hyper
library does not create secure connection by default. Apple servers expect TLS connection. This behavior of hyper
can be overriden by secure=True
in the HTTP20Connection
constructor.
Proposed solution: I propose #58 which adds a secure=True
to the HTTP20Connection
initialization.
When using token authentication, APNs starts emitting TooManyProviderTokenUpdates
errors if notifications with different topics are sent around the same time on the same connection. It looks like this happens because the TokenCredentials
class creates and stores a different token for each topic by design, and APNs doesn't want a provider token to change on a single connection more often than once every 20 minutes.
From Apple's documentation:
The provider’s authentication token is being updated too often. Update the authentication token no more than once every 20 minutes.
Preliminarily, it seems like this problem can be worked around by forcing TokenCredentials
to only ever use one JWT at a time, but this would seem to go against the intent of the library?
Hi, the last version 0.4.1 was released in May, however I would like to use changes merged in July. Could you make a new release on PyPi (0.4.2)?
I'm sending batches of ~1 million notifications. I need to send them fairly quickly, so I'm spreading the work to 10 distinct Python processes (not threads) with the multiprocessing module. Each process passes an iterator of ~100k tokens to send_notification_batch
.
This used to work very well, but since a few days, I'm getting this exception:
Traceback (most recent call last):
File "/home/ubuntu/myapp/src/myapp/apns.py", line 149, in _send_many
topic=settings.APNS_TOPIC,
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/apns2/client.py", line 174, in send_notification_batch
priority, expiration, collapse_id)
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/apns2/client.py", line 120, in send_notification_async
stream_id = self._connection.request('POST', url, json_payload, headers) # type: int
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/src/hyper/hyper/http20/connection.py", line 274, in request
self.endheaders(message_body=body, final=True, stream_id=stream_id)
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/src/hyper/hyper/http20/connection.py", line 571, in endheaders
stream.send_headers(headers_only)
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/src/hyper/hyper/http20/stream.py", line 98, in send_headers
conn.send_headers(self.stream_id, headers, end_stream)
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/h2/connection.py", line 844, in send_headers
headers, self.encoder, end_stream
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/h2/stream.py", line 913, in send_headers
headers, encoder, hf, hdr_validation_flags
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/h2/stream.py", line 1306, in _build_headers_frames
encoded_headers = encoder.encode(headers)
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/hpack/hpack.py", line 249, in encode
for header in headers:
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/h2/utilities.py", line 474, in inner
for header in headers:
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/h2/utilities.py", line 419, in _validate_host_authority_header
for header in headers:
File "/home/ubuntu/.pyenv/versions/3.6.2/envs/myapp/lib/python3.6/site-packages/h2/utilities.py", line 331, in _reject_pseudo_header_fields
"Received duplicate pseudo-header field %s" % header[0]
h2.exceptions.ProtocolError: Received duplicate pseudo-header field b':path'
I think it's random. I haven't been able to reproduce it at a small scale. I haven't been able to figure out with what frequency it happens yet.
I couldn't track down a change in a library that would cause this. It didn't start with a code deployment.
Here are the versions I'm using:
apns2 = 0.6.0
hyper = https://github.com/Lukasa/hyper.git@18b629b8487169870235fe13387e2ae03c178b9f
h2 = 2.6.2
The exception happens when we're preparing a request to send to APNS. If there's a bug, it's likely in hyper or h2, but hyper has been dead for 2 years, so there's no point filing a bug there.
I'm not sure there's much you can do with the information I provided :-( I'm writing the bug report in case someone else has the same issue, mostly...
In the long run, I guess it will be best to switch to httpx, but I'm not sure it does what you need yet — namely encode/httpx#52
For now, I added debug code to try to figure out what happens:
--- apns2/client.py 2019-10-12 08:43:14.000000000 +0200
+++ apns2/client.py 2019-10-12 08:42:21.000000000 +0200
@@ -117,7 +117,13 @@
headers['apns-collapse-id'] = collapse_id
url = '/3/device/{}'.format(token_hex)
- stream_id = self._connection.request('POST', url, json_payload, headers) # type: int
+ try:
+ stream_id = self._connection.request('POST', url, json_payload, headers) # type: int
+ except Exception:
+ from myapp import logging as m_logging
+ m_logger = m_logging.get_logger("apns2.debug")
+ m_logger.exception("Exception in send_notification_async", code="apns2.send_notification_async", url=url, json_payload=json_payload, headers=headers)
+ raise
return stream_id
def get_notification_result(self, stream_id: int) -> Union[str, Tuple[str, str]]:
@@ -170,8 +176,11 @@
self.update_max_concurrent_streams()
if next_notification is not None and len(open_streams) < self.__max_concurrent_streams:
logger.info('Sending to token %s', next_notification.token)
- stream_id = self.send_notification_async(next_notification.token, next_notification.payload, topic,
- priority, expiration, collapse_id)
+ try:
+ stream_id = self.send_notification_async(next_notification.token, next_notification.payload, topic,
+ priority, expiration, collapse_id)
+ except Exception:
+ results[next_notification.token] = 'Failed'
open_streams.append(RequestStream(stream_id, next_notification.token))
next_notification = next(notification_iterator, None)
I can't send a notification to 1 million people just for testing, though, so debugging will take time...
Took a bit of time to figure out what this was supposed to be set to. I originally thought it was just the app id, i.e com.example.yourApp as noted in the README -- however for VoIP pushes, you have to add a .voip suffix (see "APNs Provider Certificates" in the Apple Docs), same goes for Watch where you have to add a .complication suffix.
Hello! Thanks for your library.
I've found memory leak in client.py: APNsClient. send_notification.
After getting HTTP20Response you should call HTTP20Response.close() or wraps it with context. If you don't close response Stream objects will leak. It leaks slowly but my service sends millions of pushes daily and it takes 8GB ram for 2 days.
Please, fix it.
Thanks!
In python 2, the check whether the credential passed is a string or not is not correct as the string passed is a unicode string and hence the check will not pass. The end result leads to an attribute error in __init_connection. Offending code:
def __init__(self, credentials, use_sandbox=False, use_alternative_port=False, proto=None, json_encoder=None, password=None):
if credentials is None or isinstance(credentials, str): # Should be either unicode or basestring for python 2
self.__credentials = CertificateCredentials(credentials, password)
else:
self.__credentials = credentials
I changed it for now to test for unicode instance, however I get an IOError exception further down the road. Will investigate further.
Thank you for your work on this, I'm getting the following error:
File "/usr/local/lib/python2.7/dist-packages/apns2-0.1.0-py2.7.egg/apns2/payload.py", line 48, in __init__
super().__init__()
TypeError: super() takes at least 1 argument (0 given)
This seems to be a more serious issue which I have seen a couple of times and it does not go away with a resend and requires a restart of the daemon:
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] HPACK encoding <generator object inner at 0x7f78a12cb4a0>
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Adding (':method', 'POST') to the header table
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Encoding 3 with 7 bits
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Adding (':scheme', 'https') to the header table
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Encoding 7 with 7 bits
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Adding (':authority', 'api.development.push.apple.com') to the header table
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Encoding 64 with 7 bits
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Adding (':path', '/3/device/************************* [HIDDEN] ***************************') to the header table
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Encoding 63 with 7 bits
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Adding ('apns-topic', 'com.organization.Application') to the header table
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Encoding 62 with 7 bits
[2018-07-10 12:09:19 AM] [hpack.hpack ] [DEBUG] Encoded header block to �����
[2018-07-10 12:09:19 AM] [root ] [ERROR] [Errno 32] Broken pipe
I'm running a server on Ubuntu. It was working fine until recently. I suspect that it happened when I ran an apt upgrade. I'd appreciate any information about this error.
Excerpt from the official docs on Best Practices for Managing Connections,
Keep your connections with APNs open across multiple notifications; do not repeatedly open and close connections. APNs treats rapid connection and disconnection as a denial-of-service attack. You should leave a connection open unless you know it will be idle for an extended period of time—for example, if you only send notifications to your users once a day, it is acceptable practice to use a new connection each day.
I think it's the best for apns2-client library to conform to this best practice, in order to avoid the possibility of having the services built with the library being seeing as a denial-of-service attack and thus interruption to those services. Therefore, I think we should add a connection pool for managing the reuse of open connections to this library.
Thanks for developing this library. It has been working great for me and its code is easy to read and follow.
Could you please publish a new release to pypi.org?
There were some major improvements since last release 0.3.0 in May 2017.
Especially proxy-support and improvements to connection-handling are very needed.
Suppose my server is running code that responds to various events and those events tell the server to send push notifications to various tokens at various times. So in real time, my server may want to send 1 or 2 or 20 or 200 push notifications to various tokens (various iOS devices). Because of the way the server code is structured, I will need to use the client.send_notification function instead of send_notfication_batch. My question is this: if we have some number of (token,payload) messages to send, should we loop through all those messages and create the APNsClient object each time, ie one for each message? Or is it best to create the APNsClient once and send all the messages on the same client? Please explain. Thanks.
Hi,
While using PyAPNs2 I am facing an error from hyper. I searched but could not find any related information. Did this happen to you?
`>>> from apns2.client import APNsClient
from apns2.payload import Payload
token_hex = 'theTokenNumbers'
payload = Payload(alert="Hello World!", sound="default", badge=1)
client = APNsClient('key.pem', use_sandbox=False, use_alternative_port=False)
client.send_notification(token_hex, payload)
Traceback (most recent call last):
File "", line 1, in
File "/home/alejo/.virtualenvs/worktoday/lib/python2.7/site-packages/apns2/client.py", line 34, in send_notification
stream_id = self.__connection.request('POST', url, json_payload, headers)
File "/home/alejo/.virtualenvs/worktoday/lib/python2.7/site-packages/hyper/http20/connection.py", line 188, in request
self.endheaders(message_body=body, final=True, stream_id=stream_id)
File "/home/alejo/.virtualenvs/worktoday/lib/python2.7/site-packages/hyper/http20/connection.py", line 374, in endheaders
self.connect()
File "/home/alejo/.virtualenvs/worktoday/lib/python2.7/site-packages/hyper/http20/connection.py", line 260, in connect
assert proto in H2_NPN_PROTOCOLS or proto == H2C_PROTOCOL
AssertionError`
Thanks!
def process_notification(message):
apns = apnsClient
apns_response = None
try:
stream_id = apns.send_notification_async(device_token, apns_payload, target_app)
apns_response = apns.get_notification_result(stream_id)
except e:
logging.error(f"APNS server error occurred.Reason: {apns_response}")
if __name__ == '__main__':
# To use token based authentication
auth_key_path = 'AuthKey.p8'
auth_file = os.path.join(sys.path[0], auth_key_path)
auth_key_id = '************'
team_id = '********'
token_credentials = TokenCredentials(auth_key_path=auth_file, auth_key_id=auth_key_id, team_id=team_id)
apnsClient = APNsClient(credentials=token_credentials, use_sandbox=False)
subscriber.subscribe(subscription_name, process_notification, auto_ack_on_received=False)
while True:
time.sleep(60)
Getting "Exception: TooManyProviderTokenUpdates" not very frequently but 3-4 times a day for continuous 1 hour.
What's misconfiguration I have done that is causing the issue?
Could anyone please assist me?
Thank you.
Line 41 in 3409ff5
We send out about 2.4 million APNS requests every day. Anywhere from 30 to 40 run into an exception with this backtrace:
Traceback (most recent call last): -- File /srv/sites/marcopolo/notify/push_apns.py, line 154,
in push_apns conn.send_notification(token_hex=push_token, notification=notification, topic=topic, expiration=expiry)
File /opt/venv-marcopolo/src/apns2/apns2/client.py, line 38, in send_notification resp = self.__connection.get_response(stream_id)
File /opt/venv-marcopolo/local/lib/python2.7/site-packages/hyper/http20/connection.py, line 293, in get_response return HTTP20Response(stream.getheaders(), stream)
File /opt/venv-marcopolo/local/lib/python2.7/site-packages/hyper/http20/stream.py, line 223, in getheaders self._recv_cb(stream_id=self.stream_id)
File /opt/venv-marcopolo/local/lib/python2.7/site-packages/hyper/http20/connection.py, line 744, in _recv_cb self._single_read()
/opt/venv-marcopolo/local/lib/python2.7/site-packages/hyper/http20/connection.py, line 644, in _single_read self._sock.fill()
AttributeError: 'NoneType' object has no attribute 'fill'
Not sure what causes it. Maybe some sort of race condition? This happens in a background job system which does use threads, so maybe there is a race condition in the library where it removes the self._sock objects from the connection in one thread and tries to use it in another? I'm not totally convinced that's the problem though because it happens in short bursts across multiple webservers. Maybe some sort of network disruption event causes it?
Hi,
Would it be possible to have a tagged release with JWT support? :)
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.