manatlan/guy

How to call function on client from server?

Closed this issue · 9 comments

I am trying to replace the eel package with the guy package. One thing I can not understand from the documentation is how I would go about calling a function on the client (javascript) from my python backend. So what I am trying to do is:
Python:

def print_on_client(message):
    guy.call("print", message)

print_on_client("hello world")

Javascript:

function print(message){
    console.log(message);
}

I would expect the client printing "hello world" in the console.
What would be the correct way to achieving this?

Not like eel ...guy doesn't provide a way to call (rpc) the client directly.
In the guy's world : it's a non-sense, because guy can be runned in served mode (1 server + many clients). But guy provides another mechanism : the pub/sub ... client must subscribe/listen to an event ... and server (or other clients) can publish an "event" ...

See : https://github.com/manatlan/guy/blob/master/testPyInit.py ... you can replace the self.emit(), by self.emitMe() to send the event, only, to the connected client ...

BTW, I don't see any real life need to implement this kind of thing (i'd like to hear ones) ...
and BTW2 : it could be really easy, for me, to provide a layer on top of this (pub/sub) to provide this kind of thing, in a near future.

Thanks for the answer. I assumed it would be a different approach its just in my current eel version of my app I have a lot of back and forth with js calling python and python calling js. I just wanted to know if there is a way to convert the code easily.

I will see if I can rewrite my code with this different approach.
Just one more question - is my understanding correct that this doesn't work:

async def test(self, message):
    await self.emit("print", message)
test("hello world")

and always needs this:

async def test(self, message):
    await self.emit("print", message)
asyncio.ensure_future(test("hello world"))

So everytime I want to call a function from python I need to start a coroutine?
Sorry for the questions I am new to working asynchronous

Not like eel ... A guy's app is a python's class ...
(Every method declared in the class is exposed in client side (as js method))
If you are in the python's method (so, in the server main's loop), you don't need to start a couroutine.
Mainly, you don't need to start a coroutine, because all your code will be in the guy's class.
(think that the class is the mirror/proxy of the client, there is an independant instance by client... because there can exists multiple clients (in server mode only))

If you need to put your interaction outside of the class : you've got a trouble of design ... and you loose the context (1 client == 1 instance class), and you should manage yourself which client for which instance ... (but depending on your need : it can work ... but not with guy's full power)

If you got a (simple/short) eel's app ... I can show you how it will be in a guy's class ... no problem
You will understand quickly (i'd like to do this exercice)

Btw, to clarify my explanations ...

Here is the eel's "hello world" :
https://github.com/samuelhwilliams/Eel/tree/master/examples/01%20-%20hello_world

And here is the guy's version of ^^:
https://github.com/manatlan/guy/blob/master/testEelHelloWorld.py

Both are doing the same thing ...

the guy version is all in one file : the html/js and the python ... but you could put the html/js in a "static/Hello.html" file, it's the same thing.

Thank you very much for clarifying @manatlan!
Unfortunately when I just copy the code from: https://github.com/manatlan/guy/blob/master/testEelHelloWorld.py
I get this result in the python console:

\.pyenv\guytest\lib\site-packages\guy.py:617: RuntimeWarning: coroutine 'Hello.init' was never awaited
  new.init(new)
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
Hello from Javascript World!

and the browser window only says "Hello from Javascript World!"
I got that message with all my tests before so I thought I might be doing something wrong but now I don't know anymore. Any Ideas?

Perfect now it works! Thanks for the help, now I understand the logic.

Stay tuned ...

coz, the next version will implement a way to call directly a js method ... from py side, without using events (I'm making a layer on top of that, to abstract the concept)

you could use :

    await self.js.say_hello_js("Python World!")

in place of :

    await self.emitMe("say_hello_js","Python World!")

The 0.4.3 is here ...
See : https://github.com/manatlan/guy/blob/master/testEelHelloWorld.py

I will update the doc ;-) ... it's a nice feature