{"id":165,"date":"2018-07-15T23:22:38","date_gmt":"2018-07-15T21:22:38","guid":{"rendered":"http:\/\/www.arnorehn.de\/blog\/?p=165"},"modified":"2023-01-11T22:32:55","modified_gmt":"2023-01-11T21:32:55","slug":"new-client-languages-for-qt-webchannel","status":"publish","type":"post","link":"https:\/\/www.arnorehn.de\/blog\/2018\/07\/15\/new-client-languages-for-qt-webchannel\/","title":{"rendered":"New client languages for Qt WebChannel"},"content":{"rendered":"<p>At the <a href=\"http:\/\/www.menlosystems.com\/\" target=\"_blank\" rel=\"noopener\">company<\/a> I&#8217;m working at, we&#8217;re employing <a href=\"https:\/\/doc.qt.io\/qt-5\/qtwebchannel-index.html\">Qt WebChannel<\/a> for remote access to some of our software. Qt WebChannel was originally designed for interfacing with JavaScript clients, but it&#8217;s actually very well suited to interface with any kind of dynamic language.<\/p>\n<p>We&#8217;ve created client libraries for a few important languages with as few dependencies as possible: <a href=\"https:\/\/github.com\/MenloSystems\/pywebchannel\" target=\"_blank\" rel=\"noopener\">pywebchannel<\/a> (Python, no dependencies), <a href=\"https:\/\/github.com\/MenloSystems\/webchannel.net\" target=\"_blank\" rel=\"noopener\">webchannel.net<\/a> (.NET\/C#, depends on <a href=\"https:\/\/www.newtonsoft.com\/json\" target=\"_blank\" rel=\"noopener\">JSON.NET<\/a>) and <a href=\"https:\/\/github.com\/MenloSystems\/webchannelpp\" target=\"_blank\" rel=\"noopener\">webchannel++<\/a> (header-only C++14, depends on <a href=\"https:\/\/github.com\/nlohmann\/json\" target=\"_blank\" rel=\"noopener\">Niels Lohmann&#8217;s JSON library<\/a>).<\/p>\n<p>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.<\/p>\n<p>As with the original Qt WebChannel C++ classes, transports are completely user defined. When sensible, a default implementation of a transport is provided.<\/p>\n<p>Long story short, here&#8217;s an example of how to use the Python client. It&#8217;s designed to talk with the <a href=\"https:\/\/doc.qt.io\/qt-5\/qtwebchannel-chatserver-cpp-example.html\" target=\"_blank\" rel=\"noopener\"><code>chatserver<\/code> example of the Qt WebChannel module<\/a> over a WebSocket. It even supports the <code>asyncio<\/code> features of Python 3! Relevant excerpt without some of the boilerplate:<\/p>\n<pre class=\"lang:python decode:true  EnlighterJSRAW\" title=\"Excerpt from the chatclient pywebchannel example\" data-enlighter-language=\"python\">async def run(webchannel):\n    # Wait for initialized\n    await webchannel\n    print(\"Connected.\")\n\n    chatserver = webchannel.objects[\"chatserver\"]\n\n    username = None\n\n    async def login():\n        nonlocal username\n        username = input(\"Enter your name: \")\n        return await chatserver.login(username)\n\n    # Loop until we get a valid username\n    while not await login():\n        print(\"Username already taken. Please enter a new one.\")\n\n    # Keep the username alive\n    chatserver.keepAlive.connect(lambda *args: chatserver.keepAliveResponse(username))\n\n    # Connect to chat signals\n    chatserver.newMessage.connect(print_newmessage)\n    chatserver.userListChanged.connect(lambda *args: print_newusers(chatserver))\n\n    # Read and send input\n    while True:\n        msg = await ainput()\n        chatserver.sendMessage(username, msg)\n\n\nprint(\"Connecting...\")\nloop = asyncio.get_event_loop()\nproto = loop.run_until_complete(websockets.client.connect(CHATSERVER_URL, create_protocol=QWebChannelWebSocketProtocol))\nloop.run_until_complete(run(proto.webchannel))<\/pre>\n<p><code>pywebchannel<\/code> can also be used without the <code>async\/await<\/code> syntax and should also be compatible with Python 2.<\/p>\n<p>I would also really like to push the code upstream, but I don&#8217;t know when I&#8217;ll have the time to spare. Then there&#8217;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)?<\/p>\n<p>In any case, I think the client libraries can come in handy and expand the spectrum of application of Qt WebChannel.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>At the company I&#8217;m working at, we&#8217;re employing Qt WebChannel for remote access to some of our software. Qt WebChannel was originally designed for interfacing with JavaScript clients, but it&#8217;s actually very well suited to interface with any kind of dynamic language. We&#8217;ve created client libraries for a few important languages with as few dependencies [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[30,32],"tags":[35,10,36,34,22,31,33],"class_list":["post-165","post","type-post","status-publish","format-standard","hentry","category-programming","category-qt","tag-net","tag-c","tag-network","tag-python","tag-qt","tag-remoting","tag-webchannel"],"_links":{"self":[{"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/posts\/165","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/comments?post=165"}],"version-history":[{"count":7,"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/posts\/165\/revisions"}],"predecessor-version":[{"id":184,"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/posts\/165\/revisions\/184"}],"wp:attachment":[{"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/media?parent=165"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/categories?post=165"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.arnorehn.de\/blog\/wp-json\/wp\/v2\/tags?post=165"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}