kukosk / pyapns_client

Simple, flexible and fast Apple Push Notifications on iOS, OSX and Safari using the HTTP/2 Push provider API.
Other
25 stars 11 forks source link

APNSServerException #4

Closed NickP005 closed 3 years ago

NickP005 commented 3 years ago

I have everything set up properly as the example code

import jwt
import cryptography
from pyapns_client import APNSClient, IOSPayloadAlert, IOSPayload, IOSNotification, APNSDeviceException, APNSServerException, APNSProgrammingException, UnregisteredException

client = APNSClient(mode=APNSClient.MODE_DEV, root_cert_path='/VPS_host/notification/pushcert.pem', auth_key_path='/VPS_host/notification/AuthKey_**********.p8', auth_key_id='*********', team_id='**********')

print("starting the notification service")

try:
    device_tokens = ["2a6912121501e4f6807c5d58446dcd9ab7427984e3b8ec1a9dd60111489e7948"]
    alert = IOSPayloadAlert(body='Some message.', title='Title')
    payload = IOSPayload(alert=alert)
    notification = IOSNotification(payload=payload, topic="me.NickP05.Mochimo-App")

    for device_token in device_tokens:
        try:
            client.push(notification=notification, device_token=device_token)
        except UnregisteredException as e:
            print(f'device is unregistered, compare timestamp {e.timestamp_datetime} and remove from db')
        except APNSDeviceException:
            print('flag the device as potentially invalid and remove from db after a few tries')
        except APNSServerException:
            print('try again later')
        except APNSProgrammingException:
            print('check your code and try again later')
        else:
            print('everything is ok')
finally:
    client.close()

but it keeps telling me "try again later". What's going on? Why I should try later?

kukosk commented 3 years ago

@NickP005 You shouldn't have to import jwt and cryptography. It should be enough to install the pip requirements using the setup.py file. Did you install pyapns_client using pip?

Regarding your issue, according to the code, the "try again later" message appears when APNSServerException is thrown. I suggest you to debug the code. APNSServerException is a base exception class, so knowing the exact exception that was thrown might help you resolving the issue. You can do it like this:

except APNSServerException as e:
    print(e)

That will tell you which exact exception got thrown and where the problem might be.

NickP005 commented 3 years ago

Yes I installed it using pip3. Wasn’t I supposed to do that? In the end I used another library which doesn’t make persistent connections.. your is better in principle but if I cannot use it it’s meaningless. Will try in a few days to use your but before: how I’m supposed to install it and use it? Thanks

kukosk commented 3 years ago

@NickP005 I'm sure you should be able to use pyapns_client. I'm using it in my project where I periodically update packages and everything is working without issues. In fact, I recently updated the version of python I'm using to 3.9 and installed all pip packages from scratch without any problems.

Are you using a virtual environment for your project? If that's the case then you should use the pip in your virtual environment to install pyapns_client. If not, then you should make sure you install it for the correct python. You can have multiple versions of python installed on one machine, so I can't really tell you which pip you should use. It depends on which python you're using for your project. Maybe try using pip --version to see which python your pips correspond to.

I would definitely check pip list after the install to check if pyapns_client and all the required packages got installed. You can find the list of required packages in pyapns_client/setup.py.

After you do all of that and you're sure that you have everything installed correctly, try running the example code once again. Just make sure you configure it correctly - APNSClient.MODE_DEV / APNSClient.MODE_PROD based on if you're trying to send the push notification to a dev / prod token. If you have the root cert included in your trust store, you can pass None to root_cert_path.

If you're still seeing the issue, please try debugging it using the code I sent in my previous message. That should tell you enough information to know what exactly went wrong.

marcinsikora45 commented 3 years ago

Hi @kukosk @NickP005 , I have this same problem: APNSServerException I have logged more and reached to these logs: [D 211110 08:41:43.683 client:118] Creating a new client instance. [D 211110 08:41:43.686 client:106] Creating a new authentication token. [D 211110 08:41:43.986 client:75] Failed to receive a response: ConnectError. [D 211110 08:41:43.987 client:136] Resetting the existing client instance.

It seems that it is httpx ConnectError exception.

Going further it is good to do this:

except APNSServerException as e:
    logger.error(f'Server Exception: {e}', exc_info=True)

Thanks to that I received more info on error:

        response = self._send_request(headers=headers, json_data=json_data, device_token=device_token)
      File "/var/www/gta/lib/python3.10/site-packages/pyapns_client-2.0.2-py3.10.egg/pyapns_client/client.py", line 97, in _send_request
        return self._client.post(url, data=json_data, headers=headers)
      File "/var/www/gta/lib/python3.10/site-packages/httpx/_client.py", line 1095, in post
        return self.request(
      File "/var/www/gta/lib/python3.10/site-packages/httpx/_client.py", line 792, in request
        return self.send(request, auth=auth, follow_redirects=follow_redirects)
      File "/var/www/gta/lib/python3.10/site-packages/httpx/_client.py", line 877, in send
        response = self._send_handling_auth(
      File "/var/www/gta/lib/python3.10/site-packages/httpx/_client.py", line 905, in _send_handling_auth
        response = self._send_handling_redirects(
      File "/var/www/gta/lib/python3.10/site-packages/httpx/_client.py", line 942, in _send_handling_redirects
        response = self._send_single_request(request)
      File "/var/www/gta/lib/python3.10/site-packages/httpx/_client.py", line 978, in _send_single_request
        response = transport.handle_request(request)
      File "/var/www/gta/lib/python3.10/site-packages/httpx/_transports/default.py", line -1, in handle_request
      File "/usr/lib/python3.10/contextlib.py", line 151, in __exit__
        self.gen.throw(type, value, traceback)
      File "/var/www/gta/lib/python3.10/site-packages/httpx/_transports/default.py", line 79, in map_httpcore_exceptions
        raise mapped_exc(message) from exc
    httpx.ConnectError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1122)

So this is something with local certificates.

kukosk commented 3 years ago

@marsikora Thanks! That helps a lot and now I think I know what's wrong @NickP005.

Aren't you passing your own push certificate to the root_cert_path param? You shouldn't need to use your own certificate with token-based auth. That's actually one of the advantages that you then don't need to renew your certificates anymore.

root_cert_path should contain the path to the root certificate AAACertificateServices from this link: https://developer.apple.com/news/?id=7gx0a2lp.

If you have that certificate in your trust store and if trust store is configured properly, then you should be able to just pass None to that param.

Please let me know if this helps and I will update the README to include this info.

marcinsikora45 commented 3 years ago

Thanks, now it works :) Even from Docker. Regards and thanks for great and helpful library.

kukosk commented 3 years ago

Thanks @marsikora!

I'm really happy to hear it works now and also that you like the library :) The documentation clearly was a bit misleading about the root certificate so I updated it and published a new version to pypi.