简体   繁体   English

Python:cmd和asyncio的组合(用于WAMP /高速公路)

[英]Python: Combination of cmd and asyncio (for WAMP / autobahn)

Overview 总览

I am trying to implement a simple command-line interface for a WAMP application. 我正在尝试为WAMP应用程序实现一个简单的命令行界面。

For the WAMP implementation, the autobahn python package is used. 对于WAMP实施,使用了autobahn python软件包。

I would like to have an interactive shell so I decided to use the cmd module to parse the input. 我想要一个交互式外壳,所以我决定使用cmd模块来解析输入。 Unfortunately, I have not been able to combine the asyncio nature of autobahn with the cmd loop. 不幸的是,我无法将autobahnasyncio特性与cmd循环结合起来。

Code

So in general what I would like to have is something similar to this: 因此,总的来说,我想拥有的东西与此类似:

import argparse
import autobahn.asyncio.wamp as wamp
import cmd

class Shell(cmd.Cmd):
    intro = 'Interactive WAMP shell. Type help or ? to list commands.\n'
    prompt = '>> '

    def __init__(self, caller, *args):
        super().__init__(*args)
        self.caller = caller

    def do_add(self, arg):
        'Add two integers'
        a, b = arg.split(' ')
        res = self.caller(u'com.example.add2', int(a), int(b))
        res = res.result() # this cannot work and yields an InvalidStateError
        print('call result: {}'.format(res))

class Session(wamp.ApplicationSession):
    async def onJoin(self, details):
        Shell(self.call).cmdloop()

def main(args):
    url = 'ws://{0}:{1}/ws'.format(args.host, args.port)
    print('Attempting connection to "{0}"'.format(url))

    try:
        runner = wamp.ApplicationRunner(url=url, realm=args.realm)
        runner.run(Session)
    except OSError as err:
        print("OS error: {0}".format(err))

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('realm', type=str)
    parser.add_argument('host', type=str)
    parser.add_argument('port', type=int)

    main(parser.parse_args())

This obviously can not work since the result is not ready when result() is called on the future, but I can not use await since the Shell is not async itself. 这显然是行不通的,因为将来调用result()时结果还没有准备好,但是由于Shell本身不是async ,所以我不能使用await。

Solution Attempts 解决方案尝试

I have found asynccmd but I could not work out how to use it with autobahn and I am in general still a bit overwhelmed by the internals of asyncio . 我已经找到asynccmd但是我asynccmd如何在autobahn上使用它的问题,并且总体上,我仍然对asyncio的内部结构有点不知所措。

Using a simple loop 使用一个简单的循环

try:
    while(True):
        a = int(input('a:'))
        b = int(input('b:'))
        res = await self.call(u'com.example.add2', a, b)
        print('call result: {}'.format(res))
except Exception as e:
    print('call error: {0}'.format(e))

inside the onJoin function works perfectly fine, so I feel like there has to be a simple and lean solution for my problem as well. 内部的onJoin函数可以很好地工作,所以我觉得我的问题也必须有一个简单而精益的解决方案。

Any suggestions would be much appreciated! 我们欢迎所有的建议!

It turns out that there already is a solution for this problem. 事实证明,已经有解决此问题的方法。

autobahn has two versions, one using aysncio and one using asynchronous callbacks from twisted . autobahn有两个版本,一个使用aysncio ,另一个使用来自twisted异步回调。

The package crochet allows the usage of twisted -callbacks from a synchronous context and therefore offers a solution. crochet程序包允许使用同步上下文中的twisted回调,因此提供了一种解决方案。

Simple Solution 简单的解决方案

The package autobahn-sync is a crochet -wrapper for autobahn and makes calling an RCP from within cmd.Cmd (or anywhere else) trivial: 软件包autobahn-synccrochet包装器,用于autobahn,可从cmd.Cmd (或其他任何地方)内调用RCP变得很简单:

import autobahn_sync

autobahn_sync.run(url='example.com', realm='myrealm')
autobahn_sync.call(u'com.example.add2', a, b)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM