At the company I’m working at, we’re employing Qt WebChannel for remote access to some of our software. Qt WebChannel was originally designed for interfacing with JavaScript clients, but it’s actually very well suited to interface with any kind of dynamic language.
We’ve created client libraries for a few important languages with as few dependencies as possible: pywebchannel (Python, no dependencies), webchannel.net (.NET/C#, depends on JSON.NET) and webchannel++ (header-only C++14, depends on Niels Lohmann’s JSON library).
Python and .NET are a pretty good match: Their dynamic language features make it possible to use remote methods and properties like they were native. Due to being completely statically typed, C++ makes the interface a little more clunky, although variadic templates help a lot to make it easier to use.
As with the original Qt WebChannel C++ classes, transports are completely user defined. When sensible, a default implementation of a transport is provided.
Long story short, here’s an example of how to use the Python client. It’s designed to talk with the chatserver
example of the Qt WebChannel module over a WebSocket. It even supports the asyncio
features of Python 3! Relevant excerpt without some of the boilerplate:
async def run(webchannel): # Wait for initialized await webchannel print("Connected.") chatserver = webchannel.objects["chatserver"] username = None async def login(): nonlocal username username = input("Enter your name: ") return await chatserver.login(username) # Loop until we get a valid username while not await login(): print("Username already taken. Please enter a new one.") # Keep the username alive chatserver.keepAlive.connect(lambda *args: chatserver.keepAliveResponse(username)) # Connect to chat signals chatserver.newMessage.connect(print_newmessage) chatserver.userListChanged.connect(lambda *args: print_newusers(chatserver)) # Read and send input while True: msg = await ainput() chatserver.sendMessage(username, msg) print("Connecting...") loop = asyncio.get_event_loop() proto = loop.run_until_complete(websockets.client.connect(CHATSERVER_URL, create_protocol=QWebChannelWebSocketProtocol)) loop.run_until_complete(run(proto.webchannel))
pywebchannel
can also be used without the async/await
syntax and should also be compatible with Python 2.
I would also really like to push the code upstream, but I don’t know when I’ll have the time to spare. Then there’s also the question of how to build and deploy the libraries. Would the qtwebchannel module install to $PYTHONPREFIX? Would it depend on a C# compiler (for which support would have to be added to qmake)?
In any case, I think the client libraries can come in handy and expand the spectrum of application of Qt WebChannel.