背景:我正在与不和谐的客户端一起托管烧瓶服务器
flask服务器仅需要将消息从客户端传递给不和谐,以及将消息从不和谐传递给客户端。
致电loop.run_until_complete(sendMsg(request))
时出现错误
我在wait_for
和sendMsg
wait_for
loop.run_until_complete()
我到处都是,却一无所获,因此不胜感激。
代码:
import discord
import json
import os
import asyncio
from flask import Flask, request, render_template
from async_timeout import timeout
from threading import Thread
from time import sleep
client = discord.Client()
messages = []
app = Flask(__name__)
def startClient():
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
client.run('token')
#
# Discord Events
#
@client.event
async def on_ready():
print('Discord Client Ready')
@client.event
async def on_message(message):
global messages
message.append(message)
#
# Flask Stuff
#
async def sendMsg(request):
await client.send_message(discord.Object('channel id'), request.form['message'])
@app.route("/chat/", methods=['GET', 'POST'])
def chatPage():
global messages
if request.method == 'GET':
return render_template('main.html')
elif request.method == 'POST':
loop = asyncio.new_event_loop()
loop.run_until_complete(sendMsg(request))
return ''
@app.route("/chat/get", methods=['GET'])
def chatGet():
return json.dumps(messages[int(request.args['lastMessageId']):])
# Start everything
os.environ["WERKZEUG_RUN_MAIN"] = 'true'
print('Starting discord.py client')
Thread(target=startClient).start()
print('Starting flask')
app.run(host='0.0.0.0', debug=True)
跟踪:
Traceback (most recent call last):
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 2309, in __call__
return self.wsgi_app(environ, start_response)
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 2295, in wsgi_app
response = self.handle_exception(e)
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1741, in handle_exception
reraise(exc_type, exc_value, tb)
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 2292, in wsgi_app
response = self.full_dispatch_request()
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1815, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1718, in handle_user_exception
reraise(exc_type, exc_value, tb)
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/_compat.py", line 35, in reraise
raise value
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1813, in full_dispatch_request
rv = self.dispatch_request()
File "/home/SuperKooks/.local/lib/python3.5/site-packages/flask/app.py", line 1799, in dispatch_request
return self.view_functions[rule.endpoint](**req.view_args)
File "/mnt/c/Users/SuperKooks/Documents/Coding/HTML/kindle-discord/app.py", line 51, in chatPage
loop.run_until_complete(sendMsg(request))
File "/usr/lib/python3.5/asyncio/base_events.py", line 387, in run_until_complete
return future.result()
File "/usr/lib/python3.5/asyncio/futures.py", line 274, in result
raise self._exception
File "/usr/lib/python3.5/asyncio/tasks.py", line 239, in _step
result = coro.send(None)
File "/mnt/c/Users/SuperKooks/Documents/Coding/HTML/kindle-discord/app.py", line 39, in sendMsg
await client.send_message(discord.Object('382416348007104513'), request.form['message'])
File "/home/SuperKooks/.local/lib/python3.5/site-packages/discord/client.py", line 1152, in send_message
data = yield from self.http.send_message(channel_id, content, guild_id=guild_id, tts=tts, embed=embed)
File "/home/SuperKooks/.local/lib/python3.5/site-packages/discord/http.py", line 137, in request
r = yield from self.session.request(method, url, **kwargs)
File "/home/SuperKooks/.local/lib/python3.5/site-packages/aiohttp/client.py", line 555, in __iter__
resp = yield from self._coro
File "/home/SuperKooks/.local/lib/python3.5/site-packages/aiohttp/client.py", line 197, in _request
with Timeout(timeout, loop=self._loop):
File "/home/SuperKooks/.local/lib/python3.5/site-packages/async_timeout/__init__.py", line 39, in __enter__
return self._do_enter()
File "/home/SuperKooks/.local/lib/python3.5/site-packages/async_timeout/__init__.py", line 76, in _do_enter
raise RuntimeError('Timeout context manager should be used '
RuntimeError: Timeout context manager should be used inside a task
答案 0 :(得分:3)
aiohttp.ClientSession()
希望在协程内部被调用。
尝试将Client()
初始化程序移至任何async def
函数中
答案 1 :(得分:1)
该问题看起来可能是由以下原因引起的:
elif request.method == 'POST':
loop = asyncio.new_event_loop()
loop.run_until_complete(sendMsg(request))
这将创建一个新的事件循环,并在新循环中运行sendMsg(request)
。但是,sendMsg
会在其自己的事件循环中运行的client
对象上调用方法。 sendMsg
应该被提交到在另一个线程中运行客户端的现有事件循环。为此,您需要:
startClient
中创建的循环,例如到client_loop
全局变量; asyncio.run_coroutine_threadsafe
替换loop = asyncio.new_event_loop(); loop.run_until_complete(sendMsg(request))
,以将协程提交到已经在其他线程中运行的事件循环中。提交代码如下:
elif request.method == 'POST':
# submit the coroutine to the event loop thread
send_fut = asyncio.run_coroutine_threadsafe(sendMsg(request), client_loop)
# wait for the coroutine to finish
send_fut.result()
答案 2 :(得分:0)
我通过将所有对asyncio.run
的调用替换为下面的asyncio_run
来解决此问题。它为我解决了这两个错误:
RuntimeError: Timeout context manager should be used inside a task
RuntimeError: This event loop is already running
def asyncio_run(future, as_task=True):
"""
A better implementation of `asyncio.run`.
:param future: A future or task or call of an async method.
:param as_task: Forces the future to be scheduled as task (needed for e.g. aiohttp).
"""
try:
loop = asyncio.get_running_loop()
except RuntimeError: # no event loop running:
loop = asyncio.new_event_loop()
return loop.run_until_complete(_to_task(future, as_task, loop))
else:
nest_asyncio.apply(loop)
return asyncio.run(_to_task(future, as_task, loop))
def _to_task(future, as_task, loop):
if not as_task or isinstance(future, Task):
return future
return loop.create_task(future)
第二个目标是能够将asyncio.run
视为JS世界中的promise.resolve
或来自.NET世界中的Task.Wait
。
答案 3 :(得分:0)
我知道这个问题已经有一段时间了,不过:
@app.listener("before_server_start")
async def setup_downloader(app, _):
app.ctx.session = aiohttp.ClientSession()
感谢 kolypto 的提示