我的第一个想法是使用threading 在单独的线程中运行websockets,但它不能在线程中使用asyncio.get_event_loop()。
因为websockets 像discord 一样使用asyncio,所以我尝试在asyncio 中使用相同的循环来启动两者。
在挖掘discord.run() 的源代码后,我发现它使用asyncio.get_event_loop().run_forever(),所以我尝试在没有asyncio.get_event_loop().run_forever() 的情况下启动websockets,它对我有用。
# --- start ---
# - websockets -
server = websockets.serve(response, '0.0.0.0', '8000')
asyncio.get_event_loop().run_until_complete(server)
# without `run_forever()` because `client.run()` will run `run_forever()`
# - discord -
TOKEN = os.getenv('DISCORD_TOKEN')
client.run(TOKEN) # `client.run()` will run `run_forever()`
我用来测试它的最小工作代码
main.py(带有discord client 和websockets server)
import os
import asyncio
import discord
import websockets
# --- websockets ----
async def response(websocket, path):
message = await websocket.recv()
print(f"[ws server] message < {message}")
#answer = f"[{message}]"
#await websocket.send(answer) # if client expect `response` then server has to send `response`
#print(f"[ws server] answer > {answer}")
# `get_channel()` has to be used after `client.run()`
channel = client.get_channel(MY_CHANNEL_ID) # access to channel
await channel.send(f'websockets: {message}')
# --- discord ---
MY_CHANNEL_ID = 709507681441808388 # you have to use own number
client = discord.Client()
# `get_channel()` has to be used after `client.run()`
#print(client.get_channel(MY_CHANNEL_ID)) # None
@client.event
async def on_message(message):
if message.author != client.user:
print('message.content:', message.content)
# --- start ---
# - websockets -
print('running websockets ws://0.0.0.0:8000')
server = websockets.serve(response, '0.0.0.0', '8000')
asyncio.get_event_loop().run_until_complete(server)
# without `run_forever()` because `client.run()` will run `run_forever()`
# - discord -
print('running discord')
TOKEN = os.getenv('DISCORD_TOKEN')
client.run(TOKEN)
client.py(websockets client,我用来测试websockets server)
import asyncio
import websockets
uri = 'ws://0.0.0.0:8000'
async def send_message():
async with websockets.connect(uri) as websocket:
message = input("msg: ")
await websocket.send(message)
print(f"[ws client] message > {message}")
#answer = await websocket.recv()
#print(f"[ws client] answer < {answer}")
asyncio.get_event_loop().run_until_complete(send_message())
顺便说一句:
您不能在client.run() 之前使用get_channel(),因为它给出了None,而我在response() 内部使用它
编辑:
我使用on_ready() 来使用get_channel() - 如果我可以访问channel,我也会签入response()。
为了确保我在开始 discord 之前设置了 channel = None。
main.py
import os
import asyncio
import discord
import websockets
# --- websockets ----
async def response(websocket, path):
global channel
message = await websocket.recv()
print(f"[ws server] message < {message}")
#answer = f"my answer: [{message}]"
#await websocket.send(answer) # if client expect `response` then server has to send `response`
#print(f"[ws server] answer > {answer}")
# `get_channel()` has to be used after `client.run()`
if not channel:
print('[ws server] getting discord channel:', MY_CHANNEL_ID)
channel = client.get_channel(MY_CHANNEL_ID) # access to channel
if not channel:
print("[ws server] can't access channel:", MY_CHANNEL_ID)
else:
print('[ws server] channel:', channel, 'message:', message)
#await channel.send(f'websockets: {message}')
await channel.send(message)
# --- discord ---
MY_CHANNEL_ID = 709507681441808388 # you have to use own number
client = discord.Client()
# `get_channel()` has to be used after `client.run()`
#print(client.get_channel(MY_CHANNEL_ID)) # None
@client.event
async def on_ready():
global channel
if not channel:
print('[on_ready] getting discord channel:', MY_CHANNEL_ID)
channel = client.get_channel(MY_CHANNEL_ID) # access to channel
if not channel:
print("[on_ready] can't access channel:", MY_CHANNEL_ID)
else:
print('[on_ready] channel:', channel)
@client.event
async def on_message(message):
if message.author != client.user:
print('[on_message] message.content:', message.content)
# --- start ---
# - websockets -
print('running websockets ws://0.0.0.0:8000')
server = websockets.serve(response, '0.0.0.0', '8000')
asyncio.get_event_loop().run_until_complete(server)
# without `run_forever()` because `client.run()` will run `run_forever()`
# - discord -
channel = None # set default value at start
print('running discord')
TOKEN = os.getenv('DISCORD_TOKEN')
client.run(TOKEN)
bot 也是如此
main-bot.py
import os
import asyncio
import discord
from discord.ext import commands
import websockets
# --- websockets ----
async def response(websocket, path):
global channel
message = await websocket.recv()
print(f"[ws server] message < {message}")
#answer = f"my answer: [{message}]"
#await websocket.send(answer) # if client expect `response` then server has to send `response`
#print(f"[ws server] answer > {answer}")
# `get_channel()` has to be used after `client.run()`
if not channel:
print('[ws server] getting discord channel:', MY_CHANNEL_ID)
channel = bot.get_channel(MY_CHANNEL_ID) # access to channel
if not channel:
print("[ws server] can't access channel:", MY_CHANNEL_ID)
else:
print('[ws server] channel:', channel, 'message:', message)
#await channel.send(f'websockets: {message}')
await channel.send(message)
# --- discord ---
MY_CHANNEL_ID = 709507681441808388 # you have to use own number
bot = commands.Bot(command_prefix="!")
# `get_channel()` has to be used after `client.run()`
#print(client.get_channel(MY_CHANNEL_ID)) # None
@bot.event
async def on_ready():
global channel
if not channel:
print('[on_ready] getting discord channel:', MY_CHANNEL_ID)
channel = bot.get_channel(MY_CHANNEL_ID) # access to channel
if not channel:
print("[on_ready] can't access channel:", MY_CHANNEL_ID)
else:
print('[on_ready] channel:', channel)
#@bot.event
#async def on_message(message):
# if message.author != bot.user:
# print('message.content:', message.content)
@bot.command()
async def ping(ctx):
await ctx.send('pong')
# --- start ---
# - websockets -
print('running websockets ws://0.0.0.0:8000')
server = websockets.serve(response, '0.0.0.0', '8000')
asyncio.get_event_loop().run_until_complete(server)
# without `run_forever()` because `client.run()` will run `run_forever()`
# - discord -
channel = None # set default value at start
print('running discord')
TOKEN = os.getenv('DISCORD_TOKEN')
bot.run(TOKEN)