Kitware / trame-server

Internal server side implementation of trame
Other
9 stars 9 forks source link

(Re?)-initializing state upon connecting client to server #30

Open cardinalgeo opened 1 day ago

cardinalgeo commented 1 day ago

Describe the bug

I've started up a trame app from the command line. I'd like to control the app from a jupyter notebook. I've tried doing this by instantiating the Client class and then connecting it to the server running on the command line using the web socket link. In a broad sense, this works, in that I can subsequently access the server's state in the jupyter notebook. However, the state available on the Client object is empty; it appears to not have been initialized/synced with the one for the app running on the command line. Why is the state not synced upon connecting the client to the server? If this non-syncing behavior is expected, how can I push a sync manually?

To Reproduce

Steps to reproduce the behavior: Run the following in the terminal as a .py file (lightly modified from the example here:

r"""
Installation requirements:
    pip install trame trame-vuetify trame-markdown
"""

import os
from trame.app import get_server
from trame.ui.vuetify import SinglePageLayout
from trame.widgets import markdown, vuetify

# -----------------------------------------------------------------------------
# Trame setup
# -----------------------------------------------------------------------------

server = get_server(client_type="vue2")
state, ctrl = server.state, server.controller

# -----------------------------------------------------------------------------
# Read markdown file
# -----------------------------------------------------------------------------

@state.change("file_name")
def update_md(file_name, **kwargs):
    md_dict = {"demo": "demo", "sample": "sample", "module": "module"}
    ctrl.md_update(md_dict[file_name])
    # md_file_path = os.path.join(os.path.dirname(__file__), file_name)
    # with open(md_file_path, encoding="utf-8") as md:
    #     ctrl.md_update(md.read())

# -----------------------------------------------------------------------------
# GUI
# -----------------------------------------------------------------------------

state.trame__title = "MD Viewer"

with SinglePageLayout(server) as layout:
    layout.title.set_text("Markdown Viewer")

    with layout.toolbar:
        vuetify.VSpacer()
        vuetify.VSelect(
            v_model=("file_name", "demo"),
            items=("options", ["demo", "sample", "module"]),
            hide_details=True,
            dense=True,
        )

    with layout.content:
        md = markdown.Markdown(classes="pa-4 mx-2")
        ctrl.md_update = md.update

# -----------------------------------------------------------------------------
# Main
# -----------------------------------------------------------------------------

if __name__ == "__main__":
    server.start(port=0)

Then, in a jupyter notebook:

from trame_server.client import Client
import asyncio
import nest_asyncio

nest_asyncio.apply()

class AppConnect:
    def __init__(self):
        self.client = Client()

    def connect(self, link):
        asyncio.ensure_future(self._connect(link))    

    async def _connect(self, link):
        await self.client.connect(link, secret="wslink-secret")

    @property
    def state(self):
        state = self.client.state
        return state.to_dict()

app_connect = AppConnect()
app_connect.connect("ws://localhost:INSERT_PORT/ws") #Insert the correct port number
app_connect.state

Platform:

trame v. 3.4.0 (trame-server v 3.2.3) Device:

x Desktop Mobile OS:

Windows x MacOS Linux Android iOS Browsers Affected:

x Chrome Firefox Microsoft Edge Safari Opera Brave IE 11

jourdain commented 1 day ago

Good point, we should trigger a get state at connection time like we do in the web client. PR are welcome ;-)

jourdain commented 15 hours ago

If you are up to it, do a PR to add a call to that rpc using something like that. Ideally within the connect call so you can update the state.