Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upstream support + example #11

Draft
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

aranc
Copy link

@aranc aranc commented Dec 14, 2020

Added upstream support: https://firebase.google.com/docs/cloud-messaging/receive-upstream

  • Allow to register a callback for handling upstream messages.
  • If a callback is registered, the pool will automatically open and maintain an XMPP connection.
  • Added a usage example: examples/upstream.py

@pep8speaks
Copy link

pep8speaks commented Dec 14, 2020

Hello @aranc! Thanks for updating this PR. We checked the lines you've touched for PEP 8 issues, and found:

Line 222:80: E501 line too long (104 > 79 characters)
Line 305:80: E501 line too long (113 > 79 characters)

Comment last updated at 2021-01-18 07:09:55 UTC

@aranc aranc mentioned this pull request Dec 14, 2020
Copy link
Owner

@Fatal1ty Fatal1ty left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello and thank you for this feature. Please take into account PEP8 mistakes and all the problems I found.

# type: (int, str, int, Optional[asyncio.AbstractEventLoop]) -> NoReturn
self.sender_id = sender_id
self.api_key = api_key
self.callback = callback
assert min_connections <= max_connections, "min_connections is greater than max_connections"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's change it from assert to ValueError exception because asserts could be disabled

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -161,21 +196,27 @@ def is_busy(self):
class FCMConnectionPool:
MAX_ATTEMPTS = 10

def __init__(self, sender_id, api_key, max_connections=10, loop=None):
def __init__(self, sender_id, api_key, callback=None, min_connections=0, max_connections=10, loop=None):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename callback to more concrete upstream_callback here and in other places

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@@ -247,6 +288,19 @@ async def send_message(self, message: Message) -> MessageResponse:
logger.error('Could not send message %s: %s',
message.message_id, e)

async def maintain_min_connections_open(self):
while True:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to stop maintaining connections if close() was called.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


await asyncio.sleep(1)

for connection in self.connections[-missing_connections:]:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If pool was closed it's better not to refresh connections here.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

self.max_connections = max_connections
self.loop = loop or asyncio.get_event_loop()
self.connections = []
self._lock = asyncio.Lock(loop=self.loop)

self.loop.set_exception_handler(self.__exception_handler)

asyncio.ensure_future(self.maintain_min_connections_open())
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's save this task in the pool and cancel it in close method.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

)
payload = FCMMessage()

payload_body = {"to":str(device_token), "message_id":str(message_id), "message_type":"ack"}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make it a little bit more PEP8 friendly and add spaces between keys and values and split this dict to multiple lines because it's already has more than 80 characters.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

try:
await self.xmpp_client.stream.send(msg)
except Exception:
self.requests.pop(message.message_id)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NameError will be raised but anyway why do we need pop here? self.requests contains futures for downstream messages.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree. The pop must be removed. (Therefore the try/except control-flow can also be removed)
Fixed.

while True:
missing_connections = max(0, self.min_connections - len(self.connections))
if missing_connections > 0:
logger.debug('Creating %d missing connections' % missing_connections)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't use string formatting in logger messages in this way because some things like Sentry would consider this as different events. So, replace percent with comma.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

aiofcm/client.py Outdated
@@ -7,9 +7,12 @@


class FCM:
def __init__(self, sender_id, api_key, max_connections=10, loop=None):
def __init__(self, sender_id, api_key, callback=None, min_connections=None, max_connections=10, loop=None):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rename callback to upstream_callback.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed

@aranc
Copy link
Author

aranc commented Dec 19, 2020

No prob. Fixed style issues, will check other issues soon

@aranc
Copy link
Author

aranc commented Dec 19, 2020

Done. Resolved all current issues in review

@aranc
Copy link
Author

aranc commented Dec 19, 2020

Just to be cleaner, also adding a commit to "Don't start maintain_connections_task if min_connections==0"

@aranc aranc marked this pull request as draft January 18, 2021 05:46
@aranc aranc requested a review from Fatal1ty January 18, 2021 05:51
@aranc
Copy link
Author

aranc commented Jan 18, 2021

Hi, I added a commit to remove destroyed connections from the list of connections maintained by the connections pool. I'm not sure at all if this is the best way to approach this, but it fixes an issue I had with the upstream connection being destroyed without any new connection being opened to replace it.

Some possible issues with this fix:

  1. I added a flag to the connection object: stream_destroyed. Maybe there is already a more proper existing state or indicator
  2. Currently I'm only doing the pruning in maintain_connections_task. This is sufficient to workaround the issue, but is probably not the best option. (This might suggest an existing issue in the downstream flow: what happens when the pool tries to reacquire a destroyed connection?)

I'm opening this review for future discussion, probably not ready for merge yet

@aranc aranc marked this pull request as ready for review January 18, 2021 05:58
@aranc aranc marked this pull request as draft January 18, 2021 06:37
@aranc aranc closed this Jan 18, 2021
@aranc aranc reopened this Jan 18, 2021
@aranc aranc closed this Jan 18, 2021
@aranc aranc reopened this Jan 18, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants