Python:cmd 和 asyncio 的组合(用于 WAMP / 高速公路)
Python: Combination of cmd and asyncio (for WAMP / autobahn)
概述
我正在尝试为 WAMP 应用程序实现一个简单的命令行界面。
对于 WAMP 实现,使用 autobahn
python 包。
我想要一个交互式的 shell 所以我决定使用 cmd
模块来解析输入。不幸的是,我无法将 autobahn
的 asyncio
性质与 cmd
循环结合起来。
代码
所以总的来说,我想要的是类似这样的东西:
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())
这显然是行不通的,因为在将来调用 result()
时结果还没有准备好,但我不能使用等待,因为 Shell 本身不是 async
。
解决方案尝试
我找到了 asynccmd
,但我无法弄清楚如何将它与 autobahn
一起使用,而且总的来说,我仍然对 asyncio
的内部结构有些不知所措。
使用简单的循环
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))
在 onJoin
函数中工作得非常好,所以我觉得我的问题也必须有一个简单而精益的解决方案。
如有任何建议,我们将不胜感激!
原来这个问题已经有了解决方案
autobahn
有两个版本,一个使用 aysncio
,另一个使用来自 twisted
.
的异步回调
包 crochet
允许使用来自同步上下文的 twisted
回调,因此提供了一个解决方案。
简单的解决方案
包 autobahn-sync
是一个 crochet
-wrapper 用于高速公路,使得从 cmd.Cmd
(或其他任何地方)内调用 RCP 变得微不足道:
import autobahn_sync
autobahn_sync.run(url='example.com', realm='myrealm')
autobahn_sync.call(u'com.example.add2', a, b)
概述
我正在尝试为 WAMP 应用程序实现一个简单的命令行界面。
对于 WAMP 实现,使用 autobahn
python 包。
我想要一个交互式的 shell 所以我决定使用 cmd
模块来解析输入。不幸的是,我无法将 autobahn
的 asyncio
性质与 cmd
循环结合起来。
代码
所以总的来说,我想要的是类似这样的东西:
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())
这显然是行不通的,因为在将来调用 result()
时结果还没有准备好,但我不能使用等待,因为 Shell 本身不是 async
。
解决方案尝试
我找到了 asynccmd
,但我无法弄清楚如何将它与 autobahn
一起使用,而且总的来说,我仍然对 asyncio
的内部结构有些不知所措。
使用简单的循环
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))
在 onJoin
函数中工作得非常好,所以我觉得我的问题也必须有一个简单而精益的解决方案。
如有任何建议,我们将不胜感激!
原来这个问题已经有了解决方案
autobahn
有两个版本,一个使用 aysncio
,另一个使用来自 twisted
.
包 crochet
允许使用来自同步上下文的 twisted
回调,因此提供了一个解决方案。
简单的解决方案
包 autobahn-sync
是一个 crochet
-wrapper 用于高速公路,使得从 cmd.Cmd
(或其他任何地方)内调用 RCP 变得微不足道:
import autobahn_sync
autobahn_sync.run(url='example.com', realm='myrealm')
autobahn_sync.call(u'com.example.add2', a, b)