Skip to content

Vue-SocketIO callback issues #40

Open
@adamlwgriffiths

Description

@adamlwgriffiths

The example from #24 demonstrates a console log I'm seeing from Brython, "empty stack".

This seems innocuous in this case (as the callback's "self" parameter is well-formed).

But I'm also seeing it when using vue-socketio, and when using it there. Not only that, but callbacks don't seem to have a "self".

I've tried to make a minimal example below, but appreciate that setting up websockets is a bit non-standard.

This example also demonstrate's vue-socketio's inability to call the mutation functions in the Store object.
I wrote a JS equivalent of this which exhibited no issues, so it's clearly the py<->js interop.

server.py

import os
from fastapi import FastAPI
from fastapi.staticfiles import StaticFiles
from starlette.responses import FileResponse
import socketio

def relative_dir(path):
    return os.path.join(os.path.dirname(__file__), path)

app = FastAPI()

app.sio = socketio.AsyncServer(async_mode='asgi')
app.mount('/ws', socketio.ASGIApp(app.sio))

app.mount("/static", StaticFiles(directory=relative_dir('static')), name="static")

@app.get("/")
async def read_index():
    return FileResponse(relative_dir('static/index.html'))

@app.sio.event()
def connect(sid, *args, **kwargs):
    print(f'{sid} connected')

@app.sio.event()
def disconnect(sid, *args, **kwargs):
    print(f'{sid} disconnected')

if __name__ == '__main__':
    import uvicorn
    uvicorn.run("basic_server:app", host="127.0.0.1", port=5000, log_level="info")

index.html

<html>
<head>
    <title>TEST</title>
</head>
<body onload="brython({cache: true, pythonpath: ['/static']})">
    <div id="app"></div>
    <!-- socketio -->
    <script src="https://cdn.jsdelivr.net/npm/socket.io@4.5.0/client-dist/socket.io.min.js"></script>
    <!-- vue -->
    <script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vuex@3.6.2/dist/vuex.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-router@3.5.4/dist/vue-router.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-socket.io@3.0.10/dist/vue-socketio.min.js"></script>

    <script src="https://cdn.jsdelivr.net/npm/brython@3.10.6/brython.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/brython@3.10.6/brython_stdlib.min.js"></script>

    <script type="text/python">
        from textwrap import dedent
        from browser import window, document, load, html
        from vue import Vue, VueStore, VueComponent, data, computed, mutation
        from vue.decorators.base import VueDecorator, pyjs_bridge

        class Sockets(VueDecorator):
            __key__ = "sockets"
            def __init__(self, fn, name=None):
                self.__id__ = name or fn.__name__
                self.__value__ = pyjs_bridge(fn)

        def sockets(fn):
            if callable(fn):
                return Sockets(fn)
            name = fn
            def inner(fn):
                return Sockets(fn, name)
            return inner

        class Store(VueStore):
            @mutation
            def socket_connect(self):
                print(f'Store.socket_connect()')
            @mutation
            def socket_set_username(self, username):
                print(f'Store.socket_set_username({username})')

        class App(VueComponent):
            template = '<div>Hello</div>'

            @sockets
            def connect(self, *args, **kwargs):
                print(f'App.connect({self}, {args}, {kwargs})')

        store_ = Store()

        Vue.use(window.VueSocketIO.new({
            'debug': True,
            'connection': window.io({
                'path': '/ws/socket.io',
                'transports': ["websocket"],
            }),
            'vuex': {
                'store': store_,
                'actionPrefix': 'socket_',
                'mutationPrefix': 'socket_'
            },
        }))

        App("#app", store=store_)
    </script>
</body>
</html>

Browser console output:

Vue-Socket.io: Received socket.io-client instance 
Vue-Socket.io: Vuex adapter enabled 
Vue-Socket.io: Vuex socket mutations enabled 
Vue-Socket.io: Vuex socket actions enabled 
Vue-Socket.io: Vue-Socket.io plugin enabled 
Vue-Socket.io: #connect subscribe, component: undefined 
vue.min.js:6 Error: callback must be a function
    at t.value (vue-socketio.min.js:14:12327)
    at vue-socketio.min.js:14:9569
    at Array.forEach (<anonymous>)
    at Cn.mounted (vue-socketio.min.js:14:9495)
    at Be (vue.min.js:6:11407)
    at Qt (vue.min.js:6:25438)
    at vue.min.js:6:68707
    at Cn.$mount (vue.min.js:6:68726)
    at Cn.$mount (vue.min.js:6:94030)
    at Cn.t._init (vue.min.js:6:33111)

Vue-Socket.io: Broadcasting: #connect, Data: 
empty stack
App.connect(None, (), {})

There are a few things here:

  1. The "callback must be a function" error.
    Which is being triggered here in vue-socketio.

  2. The callback in App prints 'None' for its value of 'self'

  3. The "empty stack" warning from Brython when using callbacks.

I appreciate vue-socketio isn't your library, but I'm not sure where else to go for assistance.
I've tried poking around inside the vue.py, but I simply don't understand most of what it is attempting to do.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions