【问题标题】:discord bot and websocket server in one application一个应用程序中的不和谐机器人和 websocket 服务器
【发布时间】:2021-05-19 03:32:29
【问题描述】:

我想在 heroku 中创建一个应用程序,它将一些数据作为 websocket 服务器并将其作为不和谐机器人发送。

这就是我尝试实现这个想法的方式:

# -*- coding: utf-8 -*-  
import asyncio, websockets, discord   

client = discord.Client() 
channel = client.get_channel(...)
print(channel)

async def response(websocket, path): 
    global channel 
    r = await websocket.recv()
    print(r)  
    await channel.send(str(r))

PORT = os.environ.get('PORT')
start_server = websockets.serve(response, '0.0.0.0', os.environ.get('PORT'))
asyncio.get_event_loop().run_until_complete(start_server)
asyncio.get_event_loop().run_forever()

但我不知道如何在这样的代码中启动不和谐机器人,以便它与 websocket 服务器并行工作。请告诉我该怎么做。

【问题讨论】:

  • 也许你应该在单独的线程中运行websocket
  • @furas,你能举个例子吗?
  • 有数百个问题以及如何使用模块threading 的示例和教程。您必须将websocket 事件循环放入函数中并使用thread 来运行此函数。然后你可以在当前线程中使用client.run()。 IE。 threading.Thread(target=function_which_starts_websocket).start()

标签: python heroku websocket discord.py python-asyncio


【解决方案1】:

我的第一个想法是使用threading 在单独的线程中运行websockets,但它不能在线程中使用asyncio.get_event_loop()


因为websocketsdiscord 一样使用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()`

我用来测试它的最小工作代码

ma​​in.py(带有discord clientwebsockets 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.pywebsockets 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

ma​​in.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 也是如此

ma​​in-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)

【讨论】:

    猜你喜欢
    • 2021-07-11
    • 2020-12-04
    • 2021-08-30
    • 2018-03-20
    • 2021-01-25
    • 2020-04-19
    • 2023-03-28
    • 2023-04-04
    • 2021-08-26
    相关资源
    最近更新 更多