-
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
Changes from 15 commits
4e9eb3e
f294766
bc977cc
be47efe
9693ef1
34c310b
08aa63d
3a7f67e
f235268
eb9cb49
1103ba8
ce317a6
462f1cb
89b442e
93453ad
96cc36b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
import argparse | ||
import asyncio | ||
|
||
from os import getenv | ||
from pubnub.callbacks import SubscribeCallback | ||
from pubnub.pubnub_asyncio import EventEngineSubscriptionManager, PubNubAsyncio | ||
from pubnub.pnconfiguration import PNConfiguration | ||
|
||
parser = argparse.ArgumentParser(description="Chat with others using PubNub") | ||
parser.add_argument("-n", metavar="name", help="Your name", default=None, required=False) | ||
parser.add_argument("-c", metavar="channel", help="The channel you want to join", default=None, required=False) | ||
args = parser.parse_args() | ||
|
||
|
||
class ExampleCallback(SubscribeCallback): | ||
def message(self, pubnub, message): | ||
print(f"{message.publisher}> {message.message}\n") | ||
|
||
def presence(self, pubnub, presence): | ||
print(f"-- {presence.uuid} {'joined' if presence.event == 'join' else 'left'} \n") | ||
|
||
def status(self, pubnub, status): | ||
if status.is_error(): | ||
print(f"! Error: {status.error_data}") | ||
else: | ||
print(f"* Status: {status.category.name}") | ||
|
||
|
||
async def async_input(): | ||
print() | ||
await asyncio.sleep(0.1) | ||
return (await asyncio.get_event_loop().run_in_executor(None, input)) | ||
|
||
|
||
async def main(): | ||
name = args.name if hasattr(args, "name") else input("Enter your name: ") | ||
channel = args.channel if hasattr(args, "channel") else input("Enter the channel you want to join: ") | ||
|
||
print("Welcome to the chat room. Type 'exit' to leave the chat.") | ||
|
||
config = PNConfiguration() | ||
config.subscribe_key = getenv("PN_KEY_SUBSCRIBE") | ||
config.publish_key = getenv("PN_KEY_PUBLISH") | ||
config.uuid = name | ||
|
||
pubnub = PubNubAsyncio(config, subscription_manager=EventEngineSubscriptionManager) | ||
pubnub.add_listener(ExampleCallback()) | ||
|
||
pubnub.subscribe().channels(channel).with_presence().execute() | ||
|
||
while True: | ||
message = await async_input() | ||
print("\x1b[2K") | ||
if message == "exit": | ||
print("Goodbye!") | ||
break | ||
|
||
await pubnub.publish().channel(channel).message(message).future() | ||
|
||
|
||
if __name__ == '__main__': | ||
loop = asyncio.get_event_loop() | ||
loop.run_until_complete(main()) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
class PresenceStateContainer: | ||
channel_states: dict | ||
|
||
def __init__(self): | ||
self.channel_states = {} | ||
|
||
def register_state(self, state: dict, channels: list): | ||
for channel in channels: | ||
self.channel_states[channel] = state | ||
|
||
def get_state(self, channels: list): | ||
return {channel: self.channel_states[channel] for channel in channels if channel in self.channel_states} | ||
|
||
def get_channels_states(self, channels: list): | ||
return {channel: self.channel_states[channel] for channel in channels if channel in self.channel_states} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,42 +1,42 @@ | ||
from pubnub.event_engine.models import effects | ||
from pubnub.event_engine import manage_effects | ||
from pubnub.event_engine.models import invocations | ||
from pubnub.event_engine import effects | ||
|
||
|
||
class Dispatcher: | ||
_pubnub = None | ||
_managed_effects_factory = None | ||
_effects_factory = None | ||
|
||
def __init__(self, event_engine) -> None: | ||
self._event_engine = event_engine | ||
self._managed_effects = {} | ||
self._effect_emitter = manage_effects.EmitEffect() | ||
self._effect_emitter = effects.EmitEffect() | ||
|
||
def set_pn(self, pubnub_instance): | ||
self._pubnub = pubnub_instance | ||
self._effect_emitter.set_pn(pubnub_instance) | ||
|
||
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): | ||
if not self._effects_factory: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. I will look at it |
||
self._effects_factory = effects.EffectFactory(self._pubnub, self._event_engine) | ||
|
||
if isinstance(effect, effects.PNEmittableEffect): | ||
self.emit_effect(effect) | ||
if isinstance(invocation, invocations.PNEmittableInvocation): | ||
self.emit_effect(invocation) | ||
|
||
elif isinstance(effect, effects.PNManageableEffect): | ||
self.dispatch_managed_effect(effect) | ||
elif isinstance(invocation, invocations.PNManageableInvocation): | ||
self.dispatch_managed_effect(invocation) | ||
|
||
elif isinstance(effect, effects.PNCancelEffect): | ||
self.dispatch_cancel_effect(effect) | ||
elif isinstance(invocation, invocations.PNCancelInvocation): | ||
self.dispatch_cancel_effect(invocation) | ||
|
||
def emit_effect(self, effect: effects.PNEffect): | ||
def emit_effect(self, effect: invocations.PNInvocation): | ||
self._effect_emitter.emit(effect) | ||
|
||
def dispatch_managed_effect(self, effect: effects.PNEffect): | ||
managed_effect = self._managed_effects_factory.create(effect) | ||
managed_effect.run() | ||
self._managed_effects[effect.__class__.__name__] = managed_effect | ||
def dispatch_managed_effect(self, invocation: invocations.PNInvocation): | ||
effect = self._effects_factory.create(invocation) | ||
effect.run() | ||
self._managed_effects[invocation.__class__.__name__] = effect | ||
|
||
def dispatch_cancel_effect(self, effect: effects.PNEffect): | ||
if effect.cancel_effect in self._managed_effects: | ||
self._managed_effects[effect.cancel_effect].stop() | ||
del self._managed_effects[effect.cancel_effect] | ||
def dispatch_cancel_effect(self, invocation: invocations.PNInvocation): | ||
if invocation.cancel_effect in self._managed_effects: | ||
self._managed_effects[invocation.cancel_effect].stop() | ||
del self._managed_effects[invocation.cancel_effect] |
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 fromobject
(which is leftover from py2.7 btw) and only adds functionality like thisstatus.category.name
to extract the name based on the value