-
Notifications
You must be signed in to change notification settings - Fork 116
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
Presence engine - states and events #178
Conversation
7c6d680
to
2dc14cb
Compare
2dc14cb
to
4e9eb3e
Compare
ca5b2fb
to
bc977cc
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTB 2 comments
74cdb09
to
9693ef1
Compare
54b367b
to
3ce8c86
Compare
3ce8c86
to
ce317a6
Compare
def dispatch_effect(self, effect: effects.PNEffect): | ||
if not self._managed_effects_factory: | ||
self._managed_effects_factory = manage_effects.ManagedEffectFactory(self._pubnub, self._event_engine) | ||
def dispatch_effect(self, invocation: invocations.PNInvocation): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mhm, I don't think we should differentiate Effects that emit status (or anything else) from other non-cancellable Effects. They should have the same interface or method to fire them. I know it's not possible to fix it, so let's keep this comment so that others are aware of this difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will look at it
if self.invocation.region: | ||
request.region(self.invocation.region) | ||
|
||
if feature_enabled('PN_MAINTAIN_PRESENCE_STATE') and hasattr(self.pubnub, 'state_container'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious, why do you need a check like this?
hasattr(self.pubnub, 'state_container')
Isn't the internal state_container
variable always present in PubNub
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
no it's not the internal variable for PubNub. It's only in PubNubAsyncio because it's only used there. This may be redundant check. I'll verify it
class HeartbeatDelayedEffect(Effect): | ||
def __init__(self, pubnub_instance, event_engine_instance, | ||
invocation: Union[invocations.PNManageableInvocation, invocations.PNCancelInvocation]) -> None: | ||
super().__init__(pubnub_instance, event_engine_instance, invocation) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same, let's think about improving it while working on a new reconnection policy
return self._managed_invocations[invocation.__class__.__name__](self._pubnub, self._event_engine, invocation) | ||
|
||
|
||
class EmitEffect: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There should be two separate Effects for emitting messages and status, respectively. Let's leave it if this requires significant amount of work
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM - some nitpickings and questions
pubnub/event_engine/containers.py
Outdated
self.channel_states[channel] = state | ||
|
||
def get_state(self, channels: list): | ||
return {**self.get_channels_states(channels)} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Q: What exactly meant double wyłuskanie
here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's a dict extraction. Also it's redundant. I'll fix it :)
pubnub: PubNub = None | ||
event_engine = None | ||
invocation: Union[invocations.PNManageableInvocation, invocations.PNCancelInvocation] | ||
stop_event = None | ||
logger: logging.Logger | ||
task: asyncio.Task |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpicking:
It is easy to make a mistake when looking at the default values.
pubnub: PubNub = None | |
event_engine = None | |
invocation: Union[invocations.PNManageableInvocation, invocations.PNCancelInvocation] | |
stop_event = None | |
logger: logging.Logger | |
task: asyncio.Task | |
pubnub: PubNub = None | |
event_engine: StateMachine = None | |
stop_event: PNEvent = None | |
invocation: Union[invocations.PNManageableInvocation, invocations.PNCancelInvocation] | |
logger: logging.Logger | |
task: asyncio.Task |
tt = self.invocation.timetoken or 0 | ||
if hasattr(self.pubnub, 'event_loop'): | ||
self.stop_event = self.get_new_stop_event() | ||
self.run_async(self.handshake_async(channels=channels, | ||
groups=groups, | ||
timetoken=tt, | ||
stop_event=self.stop_event)) | ||
|
||
async def handshake_async(self, channels, groups, stop_event, timetoken: int = 0): | ||
request = Subscribe(self.pubnub).channels(channels).channel_groups(groups).cancellation_event(stop_event) | ||
|
||
if feature_enabled('PN_MAINTAIN_PRESENCE_STATE') and hasattr(self.pubnub, 'state_container'): | ||
state_container = self.pubnub.state_container | ||
request.state(state_container.get_state(channels)) | ||
|
||
request.timetoken(0) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you need to set the timetoken
to zero in each of the occurrences? It would be nice to have a single point of truth in case of code-reviewing-and-debugging.
In C# there was so many of the reassignments like that and it caused the bug. :/
def give_up(self, reason: PubNubException, attempt: int, timetoken: int = 0): | ||
self.logger.error(f"GiveUp called on Unspecific event. Reason: {reason}, Attempt: {attempt} TT:{timetoken}") | ||
raise PubNubException('Unspecified Invocation') | ||
|
||
def failure(self, reason: PubNubException, attempt: int, timetoken: int = 0): | ||
self.logger.error(f"Failure called on Unspecific event. Reason: {reason}, Attempt: {attempt} TT:{timetoken}") | ||
raise PubNubException('Unspecified Invocation') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same as above?
except asyncio.CancelledError: | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It only catches the CancelledError
. Is it intended?
|
||
def on_exit(self): | ||
super().on_exit() | ||
return effects.CancelHandshakeReconnectEffect() | ||
return invocations.CancelHandshakeReconnectInvocation() | ||
|
||
def disconnect(self, event: events.DisconnectEvent, context: PNContext) -> PNTransition: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IMHO all transitions should be part of Transition function
that was mentioned in the State Machine Architecture decision. This shouldn't be the logic of any State. Let's keep this comment so that others are aware of this difference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Approved. However, some areas might differ in terms of decisions/design in comparison to other SDKs. Let's skip it for now if Presence & Subscribe works as expected and let's think about any adjustments/improvements in the future.
0b66f04
to
462f1cb
Compare
examples/cli_chat.py
Outdated
print(f"{presence.event} {presence.uuid}\n") | ||
|
||
def status(self, pubnub, status): | ||
# print(status.__dict__) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
comment?
@@ -19,7 +19,7 @@ def string(cls, method): | |||
return "PATCH" | |||
|
|||
|
|||
class PNStatusCategory(object): | |||
class PNStatusCategory(Enum): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Disclaimer: For most of situations this doesn't change anything. Enum
inherits from object
(which is leftover from py2.7 btw) and only adds functionality like this status.category.name
to extract the name based on the value
@pubnub-release-bot release |
🚀 Release successfully completed 🚀 |
feat: Optional Event Engine for Subscribe Loop