Discord-py Rewrite – Basic aiohttp webserver in a Cog
Question:
I am trying to integrate a basic aiohttp webserver in a Cog (using discord-py rewrite). I am using the following code for the cog:
from aiohttp import web
import discord
from discord.ext import commands
class Youtube():
def __init__(self, bot):
self.bot = bot
async def webserver(self):
async def handler(request):
return web.Response(text="Hello, world")
app = web.Application()
app.router.add_get('/', handler)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, '192.168.1.111', 8999)
await self.bot.wait_until_ready()
await site.start()
def setup(bot):
yt = Youtube(bot)
bot.add_cog(yt)
bot.loop.create_task(yt.webserver())
It works fine upon starting the bot.
But if I reload the cog while the bot is running, I encounter an issue:
OSError: [Errno 10048] error while attempting to bind on address
(‘192.168.1.111’, 8999): only one usage of each socket address
(protocol/network address/port) is normally permitted
I cannot think of an simple/elegant way to release and re bind every time the cog is reloaded.
I would love some suggestions on this. The end goal is to have a cog that supports youtube pubsubhubbub subscriptions.
It might just be that there is a better way to integrate a basic webserver to my bot. I could use a deamon (fork) upon starting the bot for example (I already have a webserver written using HTTPServer with a BaseHTTPRequestHandler that can handle pubsubhubbub youtube subscriptions) but somehow I have my mind set on integrating it in a cog using aiohttp 🙂
Answers:
from aiohttp import web
import asyncio
import discord
from discord.ext import commands
class Youtube():
def __init__(self, bot):
self.bot = bot
async def webserver(self):
async def handler(request):
return web.Response(text="Hello, world")
app = web.Application()
app.router.add_get('/', handler)
runner = web.AppRunner(app)
await runner.setup()
self.site = web.TCPSite(runner, '192.168.1.111', 8999)
await self.bot.wait_until_ready()
await self.site.start()
def __unload(self):
asyncio.ensure_future(self.site.stop())
def setup(bot):
yt = Youtube(bot)
bot.add_cog(yt)
bot.loop.create_task(yt.webserver())
Thanks Patrick Haugh !!
Might be a bit late but for the new users you guys can try this lib dpy-http-server
A sample code for usage of the above server is here from their PyPI page
pip install dpy-http-server
import discord
import server
from aiohttp import web
class Bot(discord.Bot):
def __init__(*args, **kwargs):
super().__init__(*args, **kwargs):
self.server = server.HTTPServer(
bot=self,
host="0.0.0.0",
port=8000,
)
self.loop.create_task(self._start_webserver())
async def _start_webserver(self):
await self.wait_until_ready()
await self.server.start()
@server.add_route(path="/", method="GET")
async def home(self, request):
return web.json_response(data={"foo": bar}, status=200)
bot = Bot(command_prefix="!", description="example", intents=discord.Intents.all())
bot.run(YOUR_TOKEN)
I am trying to integrate a basic aiohttp webserver in a Cog (using discord-py rewrite). I am using the following code for the cog:
from aiohttp import web
import discord
from discord.ext import commands
class Youtube():
def __init__(self, bot):
self.bot = bot
async def webserver(self):
async def handler(request):
return web.Response(text="Hello, world")
app = web.Application()
app.router.add_get('/', handler)
runner = web.AppRunner(app)
await runner.setup()
site = web.TCPSite(runner, '192.168.1.111', 8999)
await self.bot.wait_until_ready()
await site.start()
def setup(bot):
yt = Youtube(bot)
bot.add_cog(yt)
bot.loop.create_task(yt.webserver())
It works fine upon starting the bot.
But if I reload the cog while the bot is running, I encounter an issue:
OSError: [Errno 10048] error while attempting to bind on address
(‘192.168.1.111’, 8999): only one usage of each socket address
(protocol/network address/port) is normally permitted
I cannot think of an simple/elegant way to release and re bind every time the cog is reloaded.
I would love some suggestions on this. The end goal is to have a cog that supports youtube pubsubhubbub subscriptions.
It might just be that there is a better way to integrate a basic webserver to my bot. I could use a deamon (fork) upon starting the bot for example (I already have a webserver written using HTTPServer with a BaseHTTPRequestHandler that can handle pubsubhubbub youtube subscriptions) but somehow I have my mind set on integrating it in a cog using aiohttp 🙂
from aiohttp import web
import asyncio
import discord
from discord.ext import commands
class Youtube():
def __init__(self, bot):
self.bot = bot
async def webserver(self):
async def handler(request):
return web.Response(text="Hello, world")
app = web.Application()
app.router.add_get('/', handler)
runner = web.AppRunner(app)
await runner.setup()
self.site = web.TCPSite(runner, '192.168.1.111', 8999)
await self.bot.wait_until_ready()
await self.site.start()
def __unload(self):
asyncio.ensure_future(self.site.stop())
def setup(bot):
yt = Youtube(bot)
bot.add_cog(yt)
bot.loop.create_task(yt.webserver())
Thanks Patrick Haugh !!
Might be a bit late but for the new users you guys can try this lib dpy-http-server
A sample code for usage of the above server is here from their PyPI page
pip install dpy-http-server
import discord
import server
from aiohttp import web
class Bot(discord.Bot):
def __init__(*args, **kwargs):
super().__init__(*args, **kwargs):
self.server = server.HTTPServer(
bot=self,
host="0.0.0.0",
port=8000,
)
self.loop.create_task(self._start_webserver())
async def _start_webserver(self):
await self.wait_until_ready()
await self.server.start()
@server.add_route(path="/", method="GET")
async def home(self, request):
return web.json_response(data={"foo": bar}, status=200)
bot = Bot(command_prefix="!", description="example", intents=discord.Intents.all())
bot.run(YOUR_TOKEN)