fatal1ty / aioapns Goto Github PK
View Code? Open in Web Editor NEWAn efficient APNs Client Library for Python/asyncio
License: Apache License 2.0
An efficient APNs Client Library for Python/asyncio
License: Apache License 2.0
I have a service that uses this library. After a few hours I start getting the following message for all notifications:
2024-03-20 10:30:31.906 WARNING connection:on_connection_terminated:295 - Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fe3540def10> terminated: code=ErrorCodes.NO_ERROR, additional_data=b'{"reason":"Shutdown"}', last_stream_id=1
Restarting the service resolves the issue.
My process is as follows:
Create client
def get_apn_client(...):
# ... code here
return APNs(
key=cfg.apn_key,
key_id=cfg.apn_key_id,
team_id=cfg.apn_team_id,
topic=cfg.apn_topic, # Bundle ID
use_sandbox=use_sandbox
)
Create event loop and send message to a specific user's devices
loop = asyncio.get_event_loop()
loop.run_until_complete(send_messages(self.client, devices, msg, context, origination))
Iterate over every device and send a notification
def send_messages(...):
# ... code here
for device in devices:
request = NotificationRequest(
device_token=device.deviceToken,
message=message,
notification_id=str(uuid4()), # optional
time_to_live=3, # optional
push_type=PushType.ALERT, # optional
)
await client.send_notification(request)
This is not efficient at all, I understand. I shoehorned this into a non asyncio model. That will be fixed.
Regardless, I'm creating a new client every time I send new messages. Perhaps I have to cache the APNs
client because of the connection pool? I see that the code automatically refreshes the token based on a TTL. Theoretically I can use the same client for all sends and it will automatically update the JWT as needed.
Hi, I try to send push-msg to my device. Device token generated for dev cert. I got strange error:
[2018-01-24 15:29:26] ERROR [aioamqp.protocol.run:340] error on dispatch
Traceback (most recent call last):
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/h2/connection.py", line 224, in process_input
func, target_state = self._transitions[(self.state, input_)]
KeyError: (<ConnectionState.CLOSED: 3>, <ConnectionInputs.SEND_HEADERS: 0>)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/aioamqp/protocol.py", line 333, in run
yield from self.dispatch_frame()
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/aioamqp/protocol.py", line 288, in dispatch_frame
yield from channel.dispatch_frame(frame)
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/aioamqp/channel.py", line 107, in dispatch_frame
yield from methods[(frame.class_id, frame.method_id)](frame)
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/aioamqp/channel.py", line 641, in basic_deliver
yield from callback(self, body, envelope, properties)
File "/home/max/bot_project/mobile_mos_ru_push_server/push_server/core/push_msg_sender.py", line 57, in send_push_msg
await app.apns.send_message(push_msg, device_data.token)
File "/home/max/bot_project/mobile_mos_ru_push_server/push_server/core/clients/push_clients.py", line 120, in send_message
await self.connection.send_notification(request)
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/aioapns/client.py", line 10, in send_notification
response = await self.pool.send_notification(request)
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/aioapns/connection.py", line 321, in send_notification
response = await connection.send_notification(request)
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/aioapns/connection.py", line 132, in send_notification
headers=headers
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/h2/connection.py", line 761, in send_headers
self.state_machine.process_input(ConnectionInputs.SEND_HEADERS)
File "/home/max/bot_project/mobile_mos_ru_push_server/venv/lib/python3.6/site-packages/h2/connection.py", line 229, in process_input
"Invalid input %s in state %s" % (input_, old_state)
h2.exceptions.ProtocolError: Invalid input ConnectionInputs.SEND_HEADERS in state ConnectionState.CLOSED
Hello. I got lambda timeout in AWS Lambda environment.
I set max_connections=10, and logs at the end are below.
Closing connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80ee74a10>
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80ee74a10> lost! Error: None
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80ee74a10> discarded
Connection released (total: 3)
Closing connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80c331310>
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80c331310> lost! Error: None
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80c331310> discarded
Connection released (total: 2)
Closing connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80e2a8510>
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80e2a8510> lost! Error: None
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80e2a8510> discarded
Connection released (total: 1)
Closing connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80c076750>
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80c076750> lost! Error: None
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x7fa80c076750> discarded
Connection released (total: 0)
I think when connection is lost, new connection is not created and it blocks infinite.
In my local environment (M1 Macbook), another exception shown but it is just skipped and works well.
Connection <aioapns.connection.APNsProductionClientProtocol object at 0x10dde3048> terminated: code=ErrorCodes.NO_ERROR, additional_data=b'{"reason":"BadDeviceToken"}', last_stream_id=279
Invalid input ConnectionInputs.RECV_RST_STREAM in state ConnectionState.CLOSED
Traceback (most recent call last):
File ".../lib/python3.7/site-packages/h2/connection.py", line 224, in process_input
func, target_state = self._transitions[(self.state, input_)]
KeyError: (<ConnectionState.CLOSED: 3>, <ConnectionInputs.RECV_RST_STREAM: 16>)
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/sym/.pyenv/versions/3.7.16/lib/python3.7/asyncio/sslproto.py", line 545, in data_received
self._app_protocol.data_received(chunk)
File ".../python3.7/site-packages/aioapns/connection.py", line 82, in data_received
for event in self.conn.receive_data(data):
File ".../python3.7/site-packages/h2/connection.py", line 1463, in receive_data
events.extend(self._receive_frame(frame))
File ".../python3.7/site-packages/h2/connection.py", line 1486, in _receive_frame
frames, events = self._frame_dispatch_table[frame.__class__](frame)
File ".../python3.7/site-packages/h2/connection.py", line 1786, in _receive_rst_stream_frame
ConnectionInputs.RECV_RST_STREAM
File ".../python3.7/site-packages/h2/connection.py", line 229, in process_input
"Invalid input %s in state %s" % (input_, old_state)
h2.exceptions.ProtocolError: Invalid input ConnectionInputs.RECV_RST_STREAM in state ConnectionState.CLOSED
I think python-hyper/h2#1199 issue is related with it.
Do you have any idea about this? Thank you in advance.
Hi,
In Apple's examples with curl, one needs to provide both the key and the certificate for certificate-based push.
I don't see the configuration for a key here. Does it need to be included in the pem?
Would it be possible to add the reason and timestamp coming from the API when there’s a 410 response status code?
Is the package compatible with uvloop? Getting assertion error while trying to send a request.
https://github.com/Fatal1ty/aioapns/blob/master/aioapns/connection.py#L91
Fatal error on transport TCPTransport
protocol: <uvloop.loop.SSLProtocol object at 0xffffa482f320>
transport: <TCPTransport closed=False reading=False 0xaaab13595100>
Traceback (most recent call last):
File "uvloop/handles/stream.pyx", line 1007, in uvloop.loop.__uv_stream_buffered_on_read
File "uvloop/loop.pyx", line 109, in uvloop.loop.run_in_context1
File "uvloop/sslproto.pyx", line 379, in uvloop.loop.SSLProtocol.buffer_updated
File "uvloop/sslproto.pyx", line 505, in uvloop.loop.SSLProtocol._do_handshake
File "uvloop/sslproto.pyx", line 541, in uvloop.loop.SSLProtocol._on_handshake_complete
File "/tmp/.venv/lib/python3.10/site-packages/aioapns/connection.py", line 169, in connection_made
super(APNsBaseClientProtocol, self).connection_made(transport)
File "/tmp/.venv/lib/python3.10/site-packages/aioapns/connection.py", line 91, in connection_made
assert isinstance(transport, asyncio.Transport)
AssertionError
Under Python 3.7.1, even importing the module fails..
Python 3.7.1 (default, Apr 3 2019, 17:03:30)
[GCC 4.8.5 20150623 (Red Hat 4.8.5-28)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import aioapns
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/local/lib/python3.7/site-packages/aioapns/__init__.py", line 1, in <module>
from aioapns.client import APNs
File "/usr/local/lib/python3.7/site-packages/aioapns/client.py", line 4, in <module>
from aioapns.connection import APNsCertConnectionPool, APNsKeyConnectionPool
File "/usr/local/lib/python3.7/site-packages/aioapns/connection.py", line 126, in <module>
class APNsBaseClientProtocol(H2Protocol):
File "/usr/local/lib/python3.7/site-packages/aioapns/connection.py", line 135, in APNsBaseClientProtocol
auth_provider: Optional[AuthorizationHeaderProvider] = None):
File "/usr/local/lib/python3.7/typing.py", line 755, in __getitem__
return self.__getitem_inner__(params)
File "/usr/local/lib/python3.7/typing.py", line 251, in inner
return func(*args, **kwds)
File "/usr/local/lib/python3.7/typing.py", line 774, in __getitem_inner__
result = _type_check(result, msg)
File "/usr/local/lib/python3.7/typing.py", line 135, in _type_check
raise TypeError(f"Plain {arg} is not valid as type argument")
TypeError: Plain typing.NoReturn is not valid as type argument
My server is currently failing when using aioapns when trying to push a notification to a device. This was working a few days ago, but I'm now getting MaxAttemptsExceeded
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] ERROR:asyncio:Exception in callback <bound method APNsBaseClientProtocol.connection_lost of <aioapns.connection.APNsDevelopmentClientProtocol object at 0x7fdc1ffc2680>>
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] handle: <Handle APNsBaseClientProtocol.connection_lost>
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] Traceback (most recent call last):
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] File "uvloop/cbhandles.pyx", line 63, in uvloop.loop.Handle._run
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] File "/usr/local/lib/python3.10/site-packages/aioapns/connection.py", line 243, in connection_lost
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] self.on_connection_lost(self)
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] File "/usr/local/lib/python3.10/site-packages/aioapns/connection.py", line 355, in discard_connection
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] self.connections.remove(connection)
2024-02-24T14:08:56.680 app[6e82e50c290e08] lhr [info] ValueError: list.remove(x): x not in list
2024-02-24T14:08:56.684 app[6e82e50c290e08] lhr [info] ERROR:aioapns:Could not connect to server:
2024-02-24T14:08:56.687 app[6e82e50c290e08] lhr [info] WARNING:aioapns:Could not send notification c416e334-bed3-4c89-a099-0ec429d3d398: ConnectionError
Many thanks for your python module, I like the compact, well-designed API. For the new watchOS 6, Apple changed the requirements to now require a new header field 'apns-push-type' in order to be delivered to watchOS. It would be nice to have support for watchOS devices in aioapns. The new requirements are described in: https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607
Again, many thanks!
How to send to mutiple device tokens?
Many thanks for implementing push-type support. It works fine for the Apple Watch when I replace the line:
push_type=PushType.ALERT, # optional
by
push_type=PushType.ALERT.value, # optional
in your example. Otherwise the enum name itself and not the value it represents is used resulting in an error.
Using this library with the latest version of PyJWT (2.0.0) yields an error
AttributeError: 'str' object has no attribute 'decode'
The source of the error is this line: https://github.com/Fatal1ty/aioapns/blob/master/aioapns/connection.py#L65
Everything works fine with PyJWT==1.7.1 or with PyJWT==2.0.0 if you remove decoding
Can we either remove the .decode('ascii')
or freeze the PyJWT version?
I am running into an endless loop when the certificate expires.
When attempting to send notifications with timeout, first timeout causes a deadlock to the sender making future request wait for a lock endlessly.
Example:
My code calls send_notifications with timeout:
response = await asyncio.wait_for(self.client.send_notification(request), timeout)
After multiple successful sends I got a timeout with:
Traceback (most recent call last):
File \"/usr/local/lib/python3.10/site-packages/aioapns/client.py\", line 58, in send_notification
response = await self.pool.send_notification(request)
File \"/usr/local/lib/python3.10/site-packages/aioapns/connection.py\", line 387, in send_notification
connection = await self.acquire()
File \"/usr/local/lib/python3.10/site-packages/aioapns/connection.py\", line 358, in acquire
connection = await self.create_connection()
File \"/usr/local/lib/python3.10/site-packages/aioapns/connection.py\", line 501, in create_connection
_, protocol = await self.loop.create_connection(
File \"/usr/local/lib/python3.10/asyncio/base_events.py\", line 1089, in create_connection
transport, protocol = await self._create_connection_transport(
File \"/usr/local/lib/python3.10/asyncio/base_events.py\", line 1119, in _create_connection_transport
await waiter
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File \"/usr/local/lib/python3.10/asyncio/tasks.py\", line 456, in wait_for
return fut.result()
asyncio.exceptions.CancelledError
but since it exits without releasing the lock it acquires - all future requests gets stuck waiting for the same lock:
Traceback (most recent call last):
File \"/usr/local/lib/python3.10/site-packages/aioapns/client.py\", line 58, in send_notification
response = await self.pool.send_notification(request)
File \"/usr/local/lib/python3.10/site-packages/aioapns/connection.py\", line 387, in send_notification
connection = await self.acquire()
File \"/usr/local/lib/python3.10/site-packages/aioapns/connection.py\", line 351, in acquire
await self._lock.acquire()
File \"/usr/local/lib/python3.10/asyncio/locks.py\", line 114, in acquire
await fut
asyncio.exceptions.CancelledError
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File \"/usr/local/lib/python3.10/asyncio/tasks.py\", line 456, in wait_for
return fut.result()
asyncio.exceptions.CancelledError
Was there a reason you chose to not use a context manager with this lock? If not is it possible to change it to use one to avoid this situation?
This lib seems to have excellent type annotations. However, mypy
does not seem to find the types when using aioapns
in my code, as it fails with an Missing library stubs or py.typed marker error.
As I understand it, aioapns
should add a py.typed
marker file with its package in order to declare itself "type hint ready"? It seems like aiohttp does this for instance.
have you used it in production environment?
await apns_key_client.send_notification(request)
yields the following error:
...
File ".../venv/lib/python3.9/site-packages/cryptography/hazmat/backends/openssl/backend.py", line 1248, in _handle_key_loading_error
raise ValueError(
ValueError: ('Could not deserialize key data. The data may be in an incorrect format, it may be encrypted with an unsupported algorithm, or it may be an unsupported key type (e.g. EC curves with explicit parameters).', [_OpenSSLErrorWithText(code=503841036, lib=60, reason=524556, reason_text=b'error:1E08010C:DECODER routines::unsupported')])
I found in this library that this occurs at the following code snippet around line 74 in connection.py
:
token = jwt.encode(
payload={"iss": self.team_id, "iat": self.__issued_at},
key=self.key,
algorithm="ES256",
headers={"kid": self.key_id},
)
I'm sure this is something I'm doing wrong somewhere. Could this be an issue with my key.p8
file? Thanks in advance for any help!
Hi,
It worked for me when I tried first, but now, after each attempt, I get this:
Could not send notification a4ae653a-827c-4a40-993e-7fe0c6a7f931: ConnectionClosed
while the client keeps trying. It actually delivers the notification each time, so I wonder why it is not releasing it.
Each unsuccessful notification is leading to a logger.error
(here https://github.com/Fatal1ty/aioapns/blame/master/aioapns/client.py#L51). This could become noisy with many notifications being sent. We'd prefer to be able to handle these errors based on the response.status, on a case-by-case basis. An example is that if the response status code is 410, we'd like to quietly deregister the token without an error notification in the system.
When adding this logging error, did you have a different token deregistering pattern in mind?
It seems like a common approach to deregistering tokens when they return a particular error code after trying to push a notification to them..
Ideally, you raise an exception here, for the user to handle.
Or maybe at least reduce the loglevel to a warning, or introduce an option to skip this logging step (so that the user can check the response status themselves)?
Disabling logging from our end would mean losing other potentially useful stuff, so we'd rather not do that.
Hi,
I had a quick question for you. You have put together a useful library.
Is there one connection being made per request? And also can send_notification take a list of device tokens?
I am trying to minimize opening and closing connections with APNS2.
Thanks,
Ganesh
Would be possible in future versions to allow the private key (key
argument to APNs) to be a string instead of a file path, or to have a separate argument (e.g. key_string
) for this purpose?
The use case for this is an application that keeps all of its private keys in an encrypted file in an external package. We don't want to keep a file containing the private key in the code base, or write temp files.
APNsKeyConnectionPool` should be using key instead of key_file
When I trying to send notification, lib starts spawning an error:
Traceback (most recent call last):
File "/Users/dmitrijsenuk/.pyenv/versions/3.7.4/lib/python3.7/asyncio/sslproto.py", line 545, in data_received
self._app_protocol.data_received(chunk)
File "/Users/dmitrijsenuk/Projects/subscriptions_api/venv/lib/python3.7/site-packages/aioapns/connection.py", line 85, in data_received
self.on_response_received(headers)
File "/Users/dmitrijsenuk/Projects/subscriptions_api/venv/lib/python3.7/site-packages/aioapns/connection.py", line 229, in on_response_received
notification_id = headers.get(b'apns-id').decode('utf8')
AttributeError: 'NoneType' object has no attribute 'decode'
Could not send notification ea9416a1-e7cb-476c-af10-cc20d5b054f0: ConnectionClosed
application protocol failed to receive SSL data
protocol: <asyncio.sslproto.SSLProtocol object at 0x11dbcad50>
transport: <_SelectorSocketTransport fd=15 read=polling write=<idle, bufsize=0>>
In the same time device continue receive same notification until I press ctrl-C.
I'm getting a 400 (BadDeviceToken)
error when running the example code using a .p8 certificate. How do I correctly get the device token?
I can see in the code that you re-generate a JWT token every time a notification is sent.
In the docs from Apple, it is said that :
APNs reports an error if you recreate your tokens more than once every 20 minutes
cf https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/establishing_a_token-based_connection_to_apns
Don't you have issues while using this library on production due to this constraint?
Lines 412 to 414 in 0d6f02c
ValueError: Cannot set verify_mode to CERT_NONE when check_hostname is enabled.
.
If these settings are swapped, then the error doesn't occur.
When using the "find my account" feature, we send one email per organization that matches the email address:
https://github.com/zulip/zulip/blob/191b1ac2be46fe4219c170ab318aa10c714cb49a/zerver/views/registration.py#L746-L759
This can lead to a deluge of emails. We should adjust the template to contain all of the organizations, listed in a single email.
Hi, I'm getting the following error on Python 3.10
File "/opt/webapps/notification/tasks/push.py", line 368, in apns_push_task
conn = apns_client.get_connection(profile_type, is_tablet)
File "/opt/lib/apple/apns_client.py", line 31, in get_connection
return _get_mobile_connection(app)
File "/opt/lib/apple/apns_client.py", line 37, in _get_mobile_connection
_CLIENTS[app] = APNs(
File "/usr/local/lib/python3.10/site-packages/aioapns/client.py", line 26, in __init__
self.pool = APNsCertConnectionPool(
File "/usr/local/lib/python3.10/site-packages/aioapns/connection.py", line 402, in __init__
super(APNsCertConnectionPool, self).__init__(
File "/usr/local/lib/python3.10/site-packages/aioapns/connection.py", line 307, in __init__
self._lock = asyncio.Lock(loop=self.loop)
File "/usr/local/lib/python3.10/asyncio/locks.py", line 77, in __init__
super().__init__(loop=loop)
File "/usr/local/lib/python3.10/asyncio/mixins.py", line 17, in __init__
raise TypeError(
TypeError: As of 3.10, the *loop* parameter was removed from Lock() since it is no longer necessary```
header_encoding property of hyper-h2 changed in version 3.0.0: Changed default value from 'utf-8' to None, find in their document: https://python-hyper.org/projects/h2/en/stable/api.html.
So i think aioapns package should explicit set header_encoding property to None.
I use the following codes to send push notification with certification.
These codes are from "base usage" of the readme file (removed the key part)
import asyncio
from uuid import uuid4
from aioapns import APNs, NotificationRequest, PushType
async def run():
apns_cert_client = APNs(
client_cert='mycert.cer',
use_sandbox=False,
)
request = NotificationRequest(
device_token='<DEVICE_TOKEN>',
message = {
"aps": {
"alert": "Hello from APNs",
"badge": "1",
}
},
notification_id=str(uuid4()), # optional
time_to_live=3, # optional
push_type=PushType.ALERT, # optional
)
await apns_cert_client.send_notification(request)
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
The certification I generated and downloaded from developer.apple.com is cer format,
if I use it directly as
client_cert='mycert.cer',
Then I will get error: ssl.SSLError: [SSL] PEM lib (_ssl.c:3900)
If I convert it to pem with code:
openssl x509 -inform der -in mycert.cer -out mycert.pem
Then change code to
client_cert='mycert.pem',
Then I will get error: ssl.SSLError: [SSL] PEM lib (_ssl.c:3921)
The full traceback:
Traceback (most recent call last):
File "/root/PythonDoc/study/testAPNs.py", line 25, in <module>
loop.run_until_complete(run())
File "/usr/lib/python3.10/asyncio/base_events.py", line 649, in run_until_complete
return future.result()
File "/root/PythonDoc/study/testAPNs.py", line 6, in run
apns_cert_client = APNs(
File "/usr/local/lib/python3.10/dist-packages/aioapns/client.py", line 37, in __init__
self.pool = APNsCertConnectionPool(
File "/usr/local/lib/python3.10/dist-packages/aioapns/connection.py", line 455, in __init__
self.ssl_context.load_cert_chain(cert_file)
ssl.SSLError: [SSL] PEM lib (_ssl.c:3921)
What should I do to get the right certification to make it work?
Interesting thing is that it is working in my local development environment. But it is not working in our production server.
I am using the latest version of this package in both environments
Hello,
I'm basically running your "usage example" script (and have been doing for lots of months), but it started throwing the aforementioned error.
I'm not entirely sure, when it started doing it, might be days or weeks.
This is the message and it repeats forever:
SSL handshake failed on verifying the certificate
protocol: <asyncio.sslproto.SSLProtocol object at 0x75c68db0>
transport: <_SelectorSocketTransport fd=6 read=polling write=<idle, bufsize=0>>
Traceback (most recent call last):
File "/usr/lib/python3.7/asyncio/sslproto.py", line 625, in _on_handshake_complete
raise handshake_exc
File "/usr/lib/python3.7/asyncio/sslproto.py", line 189, in feed_ssldata
self._sslobj.do_handshake()
File "/usr/lib/python3.7/ssl.py", line 763, in do_handshake
self._sslobj.do_handshake()
ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: unable to get local issuer certificate (_ssl.c:1056)
SSL error in data received
I tried running the code on my Mac, which gave 0 issues, but on the RaspberryPi it does. Maybe the Mac trusts some Apple servers that the Pi doesn't? Or some certificate on the Pi expired? I'm not sure how to update certs on the Pi, already tried system update / upgrade but without luck.
Hi,
Apple recommends to reuse the connection when sending a lot of messages. Is there a way to do so here?
E.g. to add p8 support to https://github.com/jazzband/django-push-notifications ?
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.