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

Unable to use channels to SEND from Python to Phoenix? #39

Open
vegabook opened this issue Jun 20, 2022 · 15 comments
Open

Unable to use channels to SEND from Python to Phoenix? #39

vegabook opened this issue Jun 20, 2022 · 15 comments
Labels
question Further information is requested

Comments

@vegabook
Copy link

vegabook commented Jun 20, 2022

Documentation and examples show how to listen from messages from Phoenix, but sending to phoenix is not documented, nor is it clear that this is even possible.

🐘 tbrowne@suprabonds:~$ ipy
Python 3.8.10 (default, Mar 15 2022, 12:22:08) 
Type 'copyright', 'credits' or 'license' for more information
IPython 8.0.1 -- An enhanced Interactive Python. Type '?' for help.
In [1]: from realtime.connection import Socket
In [2]: import inspect
In [3]: def c1(payload):
   ...:     print("C1", payload)
In [4]: URL = "ws://localhost:4000/socket/websocket"
In [5]: s = Socket(URL)
In [6]: s.connect()  # this works fine as I can see it working on Phoenix side
2022-06-19 18:20:06,987:INFO - Connection was successful
In [7]: chan1 = s.set_channel("ping")
In [8]: chan1.join().on("UPDATE", c1)
Out[8]: <realtime.channel.Channel at 0x7f988a08f3d0>
In [9]: for a in inspect.getmembers(chan1):
   ...:     print(a)
('__class__', <class 'realtime.channel.Channel'>)
('__delattr__', <method-wrapper '__delattr__' of Channel object at 0x7f988a08f3d0>)
('__dict__', {'socket': <realtime.connection.Socket object at 0x7f988a0bef70>, 'topic': 'ping', 'params': {}, 'listeners': [CallbackListener(event='UPDATE', callback=<function c1 at 0x7f988b056f70>)], 'joined': False})
('__dir__', <built-in method __dir__ of Channel object at 0x7f988a08f3d0>)
('__doc__', '\n    `Channel` is an abstraction for a topic listener for an existing socket connection.\n    Each Channel has its own topic and a list of event-callbacks that responds to messages.\n    Should only be instantiated through `connection.Socket().set_chanel(topic)`\n    Topic-Channel has a 1-many relationship.\n    ')
('__eq__', <method-wrapper '__eq__' of Channel object at 0x7f988a08f3d0>)
('__format__', <built-in method __format__ of Channel object at 0x7f988a08f3d0>)
('__ge__', <method-wrapper '__ge__' of Channel object at 0x7f988a08f3d0>)
('__getattribute__', <method-wrapper '__getattribute__' of Channel object at 0x7f988a08f3d0>)
('__gt__', <method-wrapper '__gt__' of Channel object at 0x7f988a08f3d0>)
('__hash__', <method-wrapper '__hash__' of Channel object at 0x7f988a08f3d0>)
('__init__', <bound method Channel.__init__ of <realtime.channel.Channel object at 0x7f988a08f3d0>>)
('__init_subclass__', <built-in method __init_subclass__ of type object at 0x2071780>)
('__le__', <method-wrapper '__le__' of Channel object at 0x7f988a08f3d0>)
('__lt__', <method-wrapper '__lt__' of Channel object at 0x7f988a08f3d0>)
('__module__', 'realtime.channel')
('__ne__', <method-wrapper '__ne__' of Channel object at 0x7f988a08f3d0>)
('__new__', <built-in method __new__ of type object at 0x9075a0>)
('__reduce__', <built-in method __reduce__ of Channel object at 0x7f988a08f3d0>)
('__reduce_ex__', <built-in method __reduce_ex__ of Channel object at 0x7f988a08f3d0>)
('__repr__', <method-wrapper '__repr__' of Channel object at 0x7f988a08f3d0>)
('__setattr__', <method-wrapper '__setattr__' of Channel object at 0x7f988a08f3d0>)
('__sizeof__', <built-in method __sizeof__ of Channel object at 0x7f988a08f3d0>)
('__str__', <method-wrapper '__str__' of Channel object at 0x7f988a08f3d0>)
('__subclasshook__', <built-in method __subclasshook__ of type object at 0x2071780>)
('__weakref__', None)
('_join', <bound method Channel._join of <realtime.channel.Channel object at 0x7f988a08f3d0>>)
('join', <bound method Channel.join of <realtime.channel.Channel object at 0x7f988a08f3d0>>)
('joined', False)
('listeners', [CallbackListener(event='UPDATE', callback=<function c1 at 0x7f988b056f70>)])
('off', <bound method Channel.off of <realtime.channel.Channel object at 0x7f988a08f3d0>>)
('on', <bound method Channel.on of <realtime.channel.Channel object at 0x7f988a08f3d0>>)
('params', {})
('socket', <realtime.connection.Socket object at 0x7f988a0bef70>)
('topic', 'ping')

As you can see Python inspect module does not show anything on channel chan1 that might look like a method for sending. Could you elucidate on if / how one can use this library for two-way comms? Thanks.

@anand2312 anand2312 added the question Further information is requested label Jun 21, 2022
@anand2312
Copy link
Contributor

What are you trying to achieve? I'm not very knowledgeable with supabase realtime but I thought it only supported sending you realtime updates as they happen to the database, what functionality exists that would need you sending something to the phoenix server?

@vegabook
Copy link
Author

What are you trying to achieve? I'm not very knowledgeable with supabase realtime but I thought it only supported sending you realtime updates as they happen to the database, what functionality exists that would need you sending something to the phoenix server?

Phoenix has fully bidirectional clients for multiple languages but none for python. This seems the closest but is unidirectional. I wish to communicate from python to phoenix both ways and this library looks like a good starting point. My use case is unrelated to supabase.

@anand2312
Copy link
Contributor

Ah got it. This repo has sort of been on the backburner for us while we worked on the other supabase - python features, hence the lack of features. Sadly I don't have the time right now to implement this feature, but I'd be happy to review and merge any PRs.

Unrelated but I am curious -- does your usecase leverage asyncio, or is it all sync code? I ask this because right now this project does some hacky stuff to provide a sync interface to the otherwise async websockets methods and I was planning on making this repo async only too.

@vegabook

@vegabook
Copy link
Author

Ah got it. This repo has sort of been on the backburner for us while we worked on the other supabase - python features, hence the lack of features. Sadly I don't have the time right now to implement this feature, but I'd be happy to review and merge any PRs.

Unrelated but I am curious -- does your usecase leverage asyncio, or is it all sync code? I ask this because right now this project does some hacky stuff to provide a sync interface to the otherwise async websockets methods and I was planning on making this repo async only too.

@vegabook

I'm quite happy to go fully async, so if you wanted to let me know where the hacks are, also happy to take a look at those.

I will take a stab at putting in some basic bidirectionality too.

@anand2312
Copy link
Contributor

@vegabook searching for loop.run_until_complete in realtime/connection.py should get you most of the places where we wrap async calls

@karatemir
Copy link

@silentsilas
Copy link

@vegabook Have you found a viable solution for this? I'll be giving https://github.com/wwww-wwww/phxsocket a whirl this weekend, as I also need a bidirectional Phoenix Channel client.

@ben-selas
Copy link

@silentsilas Did you manage to make phxsocket work with supabase?

@silentsilas
Copy link

Ah I just needed to be able to run a Python script, and send/receive messages from it. Elixir's Port ended up doing the job without needing to modify my scripts to use Websockets.

@artificial-cassiano
Copy link

artificial-cassiano commented Dec 16, 2022

Is it possible to have a channe.send() script? I'm not familiar with the Websocket structures Supabase uses, I tried to run a simple "websocket.send" using websocket-client library, but couldn't figure out how the channels work.

URL = f"wss://{SUPABASE_ID}.supabase.co/realtime/v1/websocket?apikey={API_KEY}&vsn=1.0.0"
# Create a WebSocket connection to the specified URL
ws = websocket.WebSocket()
ws.connect(URL)

# Send a message over the WebSocket connection
ws.send("Hello, World!")

🔼 this is received by supabase's server (I can see the number of messages being increased) but the other Python client doesn't see these messages

    channel_1 = s.set_channel("*")
    channel_1.join().on("*", callback1)

@bitnom
Copy link

bitnom commented May 6, 2023

We need this. For Python to be on the backburner is not great. I will dedicate work to this but it's difficult to know exactly what supabase is expecting. Websockets are not hard. I wish the site had a raw Websockets version of the docs. Can we at least get that?

edit: just reversing the js client

@vegabook
Copy link
Author

vegabook commented Jul 15, 2023

We need this. For Python to be on the backburner is not great. I will dedicate work to this but it's difficult to know exactly what supabase is expecting. Websockets are not hard. I wish the site had a raw Websockets version of the docs. Can we at least get that?

edit: just reversing the js client

Did you have any luck with this?

@leshems
Copy link

leshems commented Jul 16, 2023

Can't we just add .send method to channels.py to support that?

... await self.socket.ws_connection.send(message)

Wouldn't that do the job?

@MindsightsAI
Copy link

I think it implemented in #68

@vegabook
Copy link
Author

Using this blog I implemented it myself from scratch and it works very well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

9 participants