Git Product home page Git Product logo

pyapns2's People

Contributors

72squared avatar aaronjheng avatar abdelwahebmoalla avatar adityavarma1234 avatar andersk avatar arthur-a avatar cassidylaidlaw avatar dbaty avatar deceze avatar erhuabushuo avatar firkeuf avatar hzulla avatar jd20 avatar jleclanche avatar jsmolina avatar karlwnw avatar leovp avatar magnolialogic avatar matangover avatar meteran avatar minimedj avatar paulosv avatar pr0ger avatar protoss-player avatar ron8mcr avatar searchdream avatar selwin avatar sh4nks avatar shintonik avatar xfox avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pyapns2's Issues

Socket timeouts

Is there a way to set a timeout for the APNS response? I couldn't find anything in the doc to confirm this.

TooManyStreamsError Exception occurred. Max outbound streams is 1000, 1000 open

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"

Random crash when sending many notifications

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...

Can't get voip notifications to work

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.

After sending a few silent notifications it starts to fail with ('SSL routines', 'ssl3_write_pending', 'bad write retry')

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')]

TypeError: super() takes at least 1 argument (0 given)

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)

Request for new Release on pypi.org

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.

Missing cert password in APNsClient

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.

Broken pipe

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

Stream forcefully closed when trying to execute the sample code

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

check for credential string with is instance does not work correct in python 2

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.

Stream forcefully closed error

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

[Feature request] Connection pool

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.

StreamResetError while running on VM

Hey,
So, we have a Django app which uses this library for push notifications. We have succesfully tested this on our local machine and its running fine. But on our production server after deployment, we are getting StreamResetError .
error_apns
What's wrong?

SyntaxError: invalid syntax

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],
^

Certificate usage

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?

Exception: TooManyProviderTokenUpdates

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)
  1. I have two PODS running in GCP.
  2. apns2==0.5.0

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.

Unregistered Exception does not provide timestamp field

Referring to apple's spec here:

https://developer.apple.com/library/content/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/CommunicatingwithAPNs.html#//apple_ref/doc/uid/TP40008194-CH11-SW16

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.

custom key

how can i add custom keys to payload?

Support for JWT authentication tokens

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

Memory leak

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!

TooManyProviderTokenUpdates errors when sending push notifications with different topics around the same time

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?

Please clarify - sending multiple notifications

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.

ConnectionResetError()

What might be the possible reasons for this error? I'm attempting to catch the exception at the end of the 'send_notification' method.

Stream forcefully closed

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?

SSL3_WRITE_PENDING 'bad write retry'

screen shot 2017-12-05 at 18 02 58

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.

why different app

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.

Connection with alternative port fails

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.

ImportError: cannot import name 'Deque' in Python < 3.5.4

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'

greenlet.error: cannot switch to a different thread

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

ConnectionResetError raised from `hyper`

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.

Dependencies out of date

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?

'apns-expiration' header is not honoured

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

assert proto in H2_NPN_PROTOCOLS or proto == H2C_PROTOCOL AssertionError

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!

Provide instructions for generating key.pem certificate file

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!

TooManyStreamsError

It seems that the code to keep the number of streams to < 1000 doesn't work correctly
screen shot 2017-12-05 at 18 01 24

Recommended heartbeat_period value

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?

TopicDisallowed when using VoIP or Watch "Complications"

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.

AttributeError: 'NoneType' object has no attribute 'fill'

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?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.