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

autobahn wamp call works in onJoin but not in button event #58

Open
malibu1966 opened this issue Apr 22, 2021 · 3 comments
Open

autobahn wamp call works in onJoin but not in button event #58

malibu1966 opened this issue Apr 22, 2021 · 3 comments

Comments

@malibu1966
Copy link

malibu1966 commented Apr 22, 2021

Hi, I am attempting to use qt5reactor in order to do crossbar.io wamp calls from a pyqt5 application. I have it working to the point that I can do a wamp call from the onJoin callback but when I try to put the call in a button event I get an immediate 'TransportLost' exception and the call does not go through.

In the code below, the call in the onJoin callback works but the call in the message_to callback (from a button) does not.

import sys, json
import qt5reactor
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QLineEdit, QPushButton, QListView, QWidget
from PyQt5.QtCore import Qt
from autobahn.twisted.wamp import ApplicationSession
from autobahn.twisted.wamp import ApplicationRunner
from autobahn.wamp import auth
from autobahn.wamp.exception import SessionNotReady
from chatinclude import MessageModel, MessageDelegate

# Subclass QMainWindow to customise your application's main window
from twisted.internet.defer import inlineCallbacks


class MainWindow(QMainWindow, ApplicationSession):

    def __init__(self, *args, **kwargs):
        self.global_authid = "test-chat-client"
        self.global_key = "MYKEY"
        super(MainWindow, self).__init__()
        super(ApplicationSession, self).__init__(*args, **kwargs)
        # Layout the UI
        l = QVBoxLayout()

        self.message_input = QLineEdit("Enter message here")

        # Buttons for from/to messages.
        self.btn1 = QPushButton("<")
        self.btn2 = QPushButton(">")

        self.messages = QListView()
        self.messages.setResizeMode(QListView.Adjust)
        # Use our delegate to draw items in this view.
        self.messages.setItemDelegate(MessageDelegate())

        self.model = MessageModel()
        self.messages.setModel(self.model)

        self.btn1.pressed.connect(self.message_to)
        self.btn2.pressed.connect(self.message_from)

        l.addWidget(self.messages)
        l.addWidget(self.message_input)
        l.addWidget(self.btn1)
        l.addWidget(self.btn2)

        self.w = QWidget()
        self.w.setLayout(l)
        self.setCentralWidget(self.w)

    @inlineCallbacks
    def message_to(self):
        USER_ME=0
        try:
            res2 = yield self.call(u'biz.domain.register_chat')
            print("\nget data result: {}\n".format(res2))
            self.model.add_message(USER_ME, self.message_input.text())
        except Exception as e:
            print("get data call error: {0}".format(e))

    def message_from(self):
        USER_THEM=1
        self.model.add_message(USER_THEM, self.message_input.text())

    def onConnect(self):
        print("CONNECT", self.global_authid)
        self.join(u"unwait", ['wampcra'], self.global_authid)

    def onChallenge(self, challenge):
        print("CHALLENGE",challenge.method)
        if challenge.method == u"wampcra":
            signature = auth.compute_wcs(self.global_key.encode('utf8'),
                                         challenge.extra['challenge'].encode('utf8'))
            return signature.decode('ascii')
        else:
            raise Exception("don't know how to handle authmethod {}".format(challenge.method))
        return None

    @inlineCallbacks
    def onJoin(self, details):
        print("JOIN")
        try:
            res2 = yield self.call(u'biz.domain.register_chat')
            print("\nget data result: {}\n".format(res2))
        except Exception as e:
            print("get data call error: {0}".format(e))

    def onLeave(self, details):
        print("LEAVE")

    def closeEvent(self, event):
        pass


app = QApplication(sys.argv)
qt5reactor.install()
runner = ApplicationRunner(url='ws://IPADDR:9001/ws', realm='myrealm')

window = MainWindow()
window.show()
runner.run(MainWindow)
#app.exec_()
@altendky
Copy link
Member

Sorry, this notification got lost in my pile. :[

Maybe a side note, maybe not... but I would tend to recommend away from multiple inheritance like this. Seems like a lot of stuff getting mixed together.

I can't say I have any familiarity with crossbar.io beyond having heard of it. Hopefully you have gotten some help from elsewhere by now, or solved this yourself. If not, could you share the full output error? Might help me understand which side of things the issue lies on.

@malibu1966
Copy link
Author

malibu1966 commented May 21, 2021 via email

@meejah
Copy link
Contributor

meejah commented May 21, 2021

I would also not do multiple inheritance like that. You're actually instantiating MainWindow twice in the above which seems likely to be the problem.

The Component interface is newer and probably more what you'll want here and can play nicely when you want to control the even-loop (as here). ApplicationRunner or autobahn.twisted.component.run are both designed as very high-level convenience APIs .. but here I think you want Qt to control the event-loop (and not Autobahn).

This is off the top of my head here, but approximately what you'll want is:

  • make a Component instance
  • hook up on_join and on_leave listeners to notify your Qt application when the wamp connection is available
  • call .start() on the Component instance

You'll likely want to disable the "chat" button when the WAMP connection isn't active. Component will re-connect automatically, so you'll get an on_leave and then (another) on_join if that happens.

Some pseudo-code:

comp = Component(...)
window = MainWindow()

@comp.on_join
def joined(session, details):
    window.set_wamp_connection(session)

@comp.on_leave
def left(session, reason):
    window.unset_wamp_connection()

window.show()
comp.start()
# ...
# app.exec_() or whatever runs the Qt main loop .. or just reactor.run()

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

No branches or pull requests

3 participants