Issue
I want to make an application in heroku that would take some data as a websocket server and send it as a discord bot.
This is how I tried to implement this idea:
# -*- 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()
But I don't know how to launch a discord bot in such a code so that it works in parallel with the websocket server. Please tell me how to do this.
Solution
My first idea was to use threading to run websockets
in separated thread but it couldn't use asyncio.get_event_loop()
in thread.
Because websockets
uses asyncio
like discord
so I tried to start both using the same loop in asyncio
.
After digging in source code of discord.run()
I found it uses asyncio.get_event_loop().run_forever()
so I tried to start websockets
without asyncio.get_event_loop().run_forever()
and it works for me.
# --- 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()`
Minimal working code which I used to test it
main.py (with discord client
and 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
which I used to test 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())
BTW:
You can't use get_channel()
before client.run()
because it gives None
and I use it inside response()
EDIT:
I used on_ready()
to use get_channel()
- and I also check in response()
if I have access to channel
.
To make sure I set channel = None
before starting discord
.
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)
And the same for 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)
Answered By - furas
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.