healthjoy / async-firebase Goto Github PK
View Code? Open in Web Editor NEWThe lightweight asynchronous client that makes interaction with Firebase Cloud Messaging oversimplified.
License: MIT License
The lightweight asynchronous client that makes interaction with Firebase Cloud Messaging oversimplified.
License: MIT License
First of all, thank you for this great job.
I want to send multicast push notifications to hundreds of devices and each device has a specific notification_count
also the motivation body could include the name of the device's user. With the current implementation of push_multicast()
, it's impossible as the function only takes a list of device tokens, not a list of bodies
and notification_count
.
The solution I propose is to make push_multicast()
accept a list of Messages, similar to what firebase_admin does with the send_all()
function. This fixes the issue because each message can be personalized.
For now, the only alternative I used was to call hundreds of push()
by chunks of 10 in a loop. This is at the cost of performance. I expect it to be a temporary solution.
Raises TypeError: init() got multiple values for argument 'cause' when raise any subclass of AsyncFirebaseError
0001-fix-create-AsyncFirebaseError-subclass-instance.patch.txt
client = cls.get_client()
message = client.build_android_config(
data=data,
title="WOMO",
body=_(notification),
priority="high",
click_action="FLUTTER_NOTIFICATION_CLICK",
)
result = await client.push_multicast(device_tokens=tokens, android=message)
get this result
{'error': {'code': 400, 'message': 'Invalid JSON payload received. Unknown name "tokens" at \'message\': Cannot find field.', 'status': 'INVALID_ARGUMENT', 'details': [{'@type': 'type.googleapis.com/google.rpc.BadRequest', 'fieldViolations': [{'field': 'message', 'description': 'Invalid JSON payload received. Unknown name "tokens" at \'message\': Cannot find field.'}]}]}}
I've already submitted a pull request (PR #64) to add Python 3.12 support to the "async-firebase" library. This issue is just to track the progress and facilitate discussions related to the PR. Your feedback and collaboration on the PR are much appreciated.
Describe the bug
All data values are getting converted to string in the payload, even None/null. There's no way to send data={"foo": null}
as a payload.
To Reproduce
android_config: AndroidConfig = fcm_client.build_android_config(
priority="normal",
data={"foo": None}
)
response: FcmPushResponse = await fcm_client.push(device_token=device, android=android_config)
This results in the following message being sent:
{
"message": {
"token": <censored>,
"android": {
"priority": "normal",
"ttl": "604800s",
"data": {
"foo": "None"
}
}
},
"validate_only": false
}
Expected behavior
I'd expect the message generated to look like this:
{
"message": {
"token": <censored>,
"android": {
"priority": "normal",
"ttl": "604800s",
"data": {
"foo": null
}
}
},
"validate_only": false
}
Screenshots
N/A
Additional context
It looks like the issue is https://github.com/healthjoy/async-firebase/blob/master/async_firebase/client.py#L218, which explicitly casts every value in the data
key to a string. Could this be changed to remove the cast, or at least exempt nulls from it? The whole point of the data
key is to be able to pass arbitrary JSON data to your application and let the app interpret it how you wish. Force-converting everything to string makes it impossible to send some valid JSON messages.
I probably get it wrong, but it looks like Limits for client have no effect because we create a new httpx.AsyncClient with each AsyncClientBase.send_request call.
I want to limit number of connections to FCM by limiting the number of connections in httpx connection pool, but appereantly for this to work we need to reuse httpx.AsyncClient beetween send_request calls
btw. @akalex thank you for your great work.
Is your feature request related to a problem? Please describe.
I am setting up a server, and I would like to be able to receive messages. The two scenarios where this could come in handy are:
Describe the solution you'd like
A similar solution as we have for iOS, Android, Flutter, etc. You can register your device, get a token, and receive messages quickly.
Additional context
Maybe that's already possible, but the doc seems more focused on sending messages to mobile devices, hence my question. There is some documentation in Firebase for enabling this in a cloud server, but I didn't fully understand it: https://firebase.google.com/docs/cloud-messaging/server
Describe the bug
404 Response when using send_multicast
using the newest version. It works fine on 3.3.0
.
To Reproduce
Use send_multicast
method.
Additional context
Logs:
[INFO] HTTP Request: POST https://oauth2.googleapis.com/token "HTTP/1.1 200 OK"
[INFO] HTTP Request: POST https://fcm.googleapis.com/v1/projects/xxxxxxxxx/messages%3Asend/batch "HTTP/1.1 404 Not Found"
[WARNING] Unexpected HTTP response with status: 404; body: b''
Thanks!
Is your feature request related to a problem? Please describe.
The Firebase Notification object in the python Admin SDK is able to take in an "image" argument to display as part of the notification. I would like to be able to use this field when constructing a notification with the async-firebase library as well.
Describe the solution you'd like
The async-firebase Notification object should accept title, body, and image arguments to match the underlying Firebase Notification object
Describe alternatives you've considered
Alternatives would just involve not using the async library and reverting to using the Firebase Notification object, but I would miss the functionality of this library!
Additional context
N/A
Describe the bug
Python 3.12 deprecated usage of datetime.utcnow()
:
datetime: datetime.datetime’s utcnow() and utcfromtimestamp() are deprecated and will be removed in a future version. Instead, use timezone-aware objects to represent datetimes in UTC: respectively, call now() and fromtimestamp() with the tz parameter set to datetime.UTC. (Contributed by Paul Ganssle in gh-103857.)
It may be a good idea to use tz-aware datetimes now.
To Reproduce
E.g. run AsyncFirebaseClient.build_apns_config(...)
.venv/lib/python3.12/site-packages/async_firebase/client.py:232: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
"apns-expiration": str(int(datetime.utcnow().timestamp()) + ttl),
Expected behavior
No warnings are logged.
Desktop:
Smartphone:
I tried to send a push notification to my Android device, but I get the following response:
{'error': {'code': 400, 'message': 'The registration token is not a valid FCM registration token', 'status': 'INVALID_ARGUMENT', 'details': [{'@type': 'type.googleapis.com/google.firebase.fcm.v1.FcmError', 'errorCode': 'INVALID_ARGUMENT'}]}}
Any help on that?
After updating to the latest version of the library, we're encountering an error while sending messages.
Instead of https://fcm.googleapis.com//v1/projects/our-project-id/messages:send
built url looks like https://fcm.googleapis.com/v1%2Fprojects%2Four-project-id%2Fmessages:send
.
This URL format results in a 404 (Not Found) error from the FCM API.
We have tested this issue with Python versions 3.11 and 3.12.
Приветствую!
Я пишу приложение на FastApi, и хочу использовать в нем Вашу библиотеку.
К сожалению, я получаю ошибку соединения.
OS Linux
async-firebase | 2.6.1 |
Код класса, работающего с FCM, следующий:
class AIOFireBaseReposytory():
def __init__(self):
self.account_file = r"./etd-service-firebase-adminsdk-60lxs-fb9fec3fd9.json"
self.client = AsyncFirebaseClient()
self.client.creds_from_service_account_file(self.account_file)
async def send_message(self, push_message: MessageEntity,
devices: list[DeviceEntity]):
message = Notification(title=push_message.title, body=push_message.body)
android_config = self.client.build_android_config(
priority="high",
ttl=2419200,
collapse_key="push",
title=push_message.title,
body=push_message.body,
)
response = await self.client.push_multicast(device_tokens=devices,
android=android_config
)
Traceback основной ошибки:
File "/home/mike_pol/PycharmProjects/fcmnew/venv/bin/lib/python3.10/site-packages/anyio/_core/_sockets.py", line 186, in connect_tcp
addr_obj = ip_address(remote_host)
File "/usr/lib/python3.10/ipaddress.py", line 54, in ip_address
raise ValueError(f'{address!r} does not appear to be an IPv4 or IPv6 address')
ValueError: 'oauth2.googleapis.com' does not appear to be an IPv4 or IPv6 address
Can't send push-notification to topic
Code for reproduce:
from async_firebase import AsyncFirebaseClient
from async_firebase.messages import Message
async def main():
client = AsyncFirebaseClient()
client.creds_from_service_account_file("file")
android_config = client.build_android_config(
priority="high",
ttl=2419200,
collapse_key="push",
title="TEST",
body="TEST",
icon="https://happycorp.com/logo.png",
)
message = Message(android=android_config, topic="weather")
response = await client.send(message)
print(response.success, response.message_id)
if __name__ == "__main__":
asyncio.run(main())
Error:
return self._loop.run_until_complete(task)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/tikey/.pyenv/versions/3.11.1/lib/python3.11/asyncio/base_events.py", line 653, in run_until_complete
return future.result()
^^^^^^^^^^^^^^^
File "/Users/tikey/PycharmProjects/firebase-notify-test/main.py", line 20, in main
message = Message(android=android_config, topic="weather")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TypeError: Message.__init__() missing 1 required positional argument: 'token'
To fix need allow None value for async_firebase.messages.Message.token like:
token: str = field(default=None)
It only returns a json and sometime it's hard to develop
Thanks for a great project
I have a question about your usage of httpx client. As I understand from FCM documentation, after upgrading to HTTPv1 API the recommended way to send batch messages is to use multiplexing via HTTP/2 protocol.
To use it with httpx you need to install httpx[http2] and pass http2
flag to client
httpx.AsyncClient(http2=True)
otherwise it establishes connection with HTTP1.1(now it works such way)
So, my question is it was a design choice not to use http2(for some reasons) or just missed?
Describe the bug
Invalid values in data argument of client.push_multicast() leads to UnknownError('Unexpected error has happened when hitting the FCM API').
To Reproduce
import asyncio
import typing
from async_firebase import AsyncFirebaseClient
async def main():
client = AsyncFirebaseClient()
client.creds_from_service_account_file('./config.json')
device_token = 'xxxxxxx'
android_config = client.build_android_config(
priority='high',
ttl=60,
title='Test message',
body='This is a test',
)
data: typing.Dict[str, typing.Any] = {'user_id': 10}
response = await client.push_multicast(device_tokens=[device_token], data=data, android=android_config, dry_run=True)
print(response.failure_count, response.responses[0].exception)
if __name__ == "__main__":
asyncio.run(main())
Expected behavior
Proper handling of the error with specific exception with error details because they are provided by FCM in response:
b'\r\n--batch_H3WKviwlw1OiFBuquMNPomHJtcBwS2Oi\r\nContent-Type: application/http\r\nContent-ID: response-37b4e119-2d98-4544-852d-082e429c18c2\r\n\r\nHTTP/1.1 400 Bad Request\r\nVary: Origin\r\nVary: X-Origin\r\nVary: Referer\r\nContent-Type: application/json; charset=UTF-8\r\n\r\n{\n "error": {\n "code": 400,\n "message": "Invalid value at \'message.data[1].value\' (TYPE_STRING), 10",\n "status": "INVALID_ARGUMENT",\n "details": [\n {\n "@type": "type.googleapis.com/google.rpc.BadRequest",\n "fieldViolations": [\n {\n "field": "message.data[1].value",\n "description": "Invalid value at \'message.data[1].value\' (TYPE_STRING), 10"\n }\n ]\n }\n ]\n }\n}\n\r\n--batch_H3WKviwlw1OiFBuquMNPomHJtcBwS2Oi--\r\n'
python: 3.8
async-frebase: 2.0.2
android_config = client.build_android_config(
priority="high",
ttl=2419200,
collapse_key="push",
data={"discount": "15%", "key_1": "value_1", "timestamp": "2021-02-24T12:00:15"},
title="Store Changes",
body="Recent store changes",
)
result = await client.push_multicast(device_tokens=tokens, android=android_config)
get these error
File ~/Code/chat_python_lib/chat_python_lib/chat/firebase.py:66, in AsyncGoogleMessageClient.send_message(cls, data, notification, tokens)
50 message = client.build_android_config(
51 data=data,
52 title="WOMO",
(...)
55 click_action="FLUTTER_NOTIFICATION_CLICK",
56 )
57 android_config = client.build_android_config(
58 priority="high",
59 ttl=2419200,
(...)
63 body="Recent store changes",
64 )
---> 66 result = await client.push_multicast(device_tokens=tokens, android=android_config)
67 return result
File ~/Code/chat_python_lib/.venv/lib64/python3.8/site-packages/async_firebase/client.py:445, in AsyncFirebaseClient.push_multicast(self, device_tokens, android, apns, data, notification, webpush, dry_run)
431 raise ValueError(
432 f"A single ``messages.MulticastMessage`` may contain up to {MULTICAST_MESSAGE_MAX_DEVICE_TOKENS} "
433 "device tokens."
434 )
436 message = MulticastMessage(
437 tokens=device_tokens,
438 data=data or {},
(...)
442 apns=apns,
443 )
--> 445 push_notification = self.assemble_push_notification(apns_config=apns, dry_run=dry_run, message=message)
446 response = await self._send_request(push_notification)
447 return response.json()
File ~/Code/chat_python_lib/.venv/lib64/python3.8/site-packages/async_firebase/client.py:96, in AsyncFirebaseClient.assemble_push_notification(apns_config, message, dry_run)
94 if len(push_notification["message"]) == 1:
95 logging.warning("No data has been provided to construct push notification payload")
---> 96 raise ValueError("``messages.PushNotification`` cannot be assembled as data has not been provided")
97 return push_notification
ValueError: ``messages.PushNotification`` cannot be assembled as data has not been provided
Recently, when sending multicast message, AsyncFirebaseClient would close the event loop and stop working further.
I did some digging myself and found out, that it happens because of 404 response when making a "message:send" request.
Discovered cause of this was async_firebase/utils.py:49 util that has encoded a ":" symbol into "%3A", resulting in a 404 response.
Removing quote fixed the issue.
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.