Remove references to web.py
This commit is contained in:
parent
b199477a02
commit
5da071d6a5
2 changed files with 3 additions and 177 deletions
20
src/main.py
20
src/main.py
|
@ -10,7 +10,6 @@ import random
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
from web import app
|
|
||||||
from logging import FileHandler
|
from logging import FileHandler
|
||||||
|
|
||||||
import discord
|
import discord
|
||||||
|
@ -104,25 +103,12 @@ class Client(commands.Bot):
|
||||||
CONFIG["jimmy"].get("uptime_kuma_interval", 60.0)
|
CONFIG["jimmy"].get("uptime_kuma_interval", 60.0)
|
||||||
)
|
)
|
||||||
self.uptime_thread.start()
|
self.uptime_thread.start()
|
||||||
app.state.bot = self
|
|
||||||
config = uvicorn.Config(
|
|
||||||
app,
|
|
||||||
host=CONFIG["server"].get("host", "0.0.0.0"),
|
|
||||||
port=CONFIG["server"].get("port", 8080),
|
|
||||||
loop="asyncio",
|
|
||||||
lifespan="on",
|
|
||||||
server_header=False
|
|
||||||
)
|
|
||||||
server = uvicorn.Server(config=config)
|
|
||||||
self.web = self.loop.create_task(asyncio.to_thread(server.serve()))
|
|
||||||
await super().start(token, reconnect=reconnect)
|
await super().start(token, reconnect=reconnect)
|
||||||
|
|
||||||
async def close(self) -> None:
|
async def close(self) -> None:
|
||||||
if self.web:
|
if self.uptime_thread:
|
||||||
self.web.cancel()
|
self.uptime_thread.kill.set()
|
||||||
if self.thread:
|
await asyncio.get_event_loop().run_in_executor(None, self.uptime_thread.join)
|
||||||
self.thread.kill.set()
|
|
||||||
await asyncio.get_event_loop().run_in_executor(None, self.thread.join)
|
|
||||||
await super().close()
|
await super().close()
|
||||||
|
|
||||||
|
|
||||||
|
|
160
src/web.py
160
src/web.py
|
@ -1,160 +0,0 @@
|
||||||
import asyncio
|
|
||||||
import datetime
|
|
||||||
import logging
|
|
||||||
import textwrap
|
|
||||||
|
|
||||||
import psutil
|
|
||||||
import time
|
|
||||||
import pydantic
|
|
||||||
from typing import Optional, Any
|
|
||||||
from conf import CONFIG
|
|
||||||
import discord
|
|
||||||
from discord.ext.commands import Paginator
|
|
||||||
|
|
||||||
from fastapi import FastAPI, HTTPException, status, WebSocketException, WebSocket, WebSocketDisconnect, Header
|
|
||||||
|
|
||||||
class BridgeResponse(pydantic.BaseModel):
|
|
||||||
status: str
|
|
||||||
pages: list[str]
|
|
||||||
|
|
||||||
|
|
||||||
class BridgePayload(pydantic.BaseModel):
|
|
||||||
secret: str
|
|
||||||
message: str
|
|
||||||
sender: str
|
|
||||||
|
|
||||||
|
|
||||||
class MessagePayload(pydantic.BaseModel):
|
|
||||||
class MessageAttachmentPayload(pydantic.BaseModel):
|
|
||||||
url: str
|
|
||||||
proxy_url: str
|
|
||||||
filename: str
|
|
||||||
size: int
|
|
||||||
width: Optional[int] = None
|
|
||||||
height: Optional[int] = None
|
|
||||||
content_type: str
|
|
||||||
ATTACHMENT: Optional[Any] = None
|
|
||||||
|
|
||||||
event_type: Optional[str] = "create"
|
|
||||||
message_id: int
|
|
||||||
author: str
|
|
||||||
is_automated: bool = False
|
|
||||||
avatar: str
|
|
||||||
content: str
|
|
||||||
clean_content: str
|
|
||||||
at: float
|
|
||||||
attachments: list[MessageAttachmentPayload] = []
|
|
||||||
reply_to: Optional["MessagePayload"] = None
|
|
||||||
|
|
||||||
|
|
||||||
app = FastAPI(
|
|
||||||
title="JimmyAPI",
|
|
||||||
version="2.0.0a1"
|
|
||||||
)
|
|
||||||
log = logging.getLogger("jimmy.web.api")
|
|
||||||
app.state.bot = None
|
|
||||||
app.state.bridge_lock = asyncio.Lock()
|
|
||||||
app.state.last_sender_ts = 0
|
|
||||||
|
|
||||||
|
|
||||||
@app.get("/ping")
|
|
||||||
def ping():
|
|
||||||
"""Checks the bot is online and provides some uptime information"""
|
|
||||||
if not app.state.bot:
|
|
||||||
raise HTTPException(status.HTTP_503_SERVICE_UNAVAILABLE)
|
|
||||||
return {
|
|
||||||
"ping": "pong",
|
|
||||||
"online": app.state.bot.is_ready(),
|
|
||||||
"latency": max(round(app.state.bot.latency, 2), 0.01),
|
|
||||||
"uptime": round(time.time() - psutil.Process().create_time()),
|
|
||||||
"uptime.sys": time.time() - psutil.boot_time()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@app.post("/bridge", status_code=201)
|
|
||||||
async def bridge_post_send_message(body: BridgePayload):
|
|
||||||
"""Sends a message FROM matrix TO discord."""
|
|
||||||
now = datetime.datetime.now(datetime.timezone.utc)
|
|
||||||
ts_diff = (now - app.state.last_sender_ts).total_seconds()
|
|
||||||
if not app.state.bot:
|
|
||||||
raise HTTPException(status.HTTP_503_SERVICE_UNAVAILABLE)
|
|
||||||
|
|
||||||
if body.secret != CONFIG["jimmy"].get("token"):
|
|
||||||
log.warning("Authentication failure: %s was not authenticated.", body.secret)
|
|
||||||
raise HTTPException(status.HTTP_401_UNAUTHORIZED)
|
|
||||||
|
|
||||||
channel = app.state.bot.get_channel(CONFIG["server"]["channel"])
|
|
||||||
if not channel or not channel.can_send():
|
|
||||||
log.warning("Unable to send message: channel not found or not writable.")
|
|
||||||
raise HTTPException(status.HTTP_503_SERVICE_UNAVAILABLE)
|
|
||||||
|
|
||||||
if len(body.message) > 4000:
|
|
||||||
log.warning(
|
|
||||||
"Unable to send message: message too long ({:,} characters long, 4000 max).".format(len(body.message))
|
|
||||||
)
|
|
||||||
raise HTTPException(status.HTTP_413_REQUEST_ENTITY_TOO_LARGE)
|
|
||||||
|
|
||||||
paginator = Paginator(prefix="", suffix="", max_size=1990)
|
|
||||||
for line in body["message"].splitlines():
|
|
||||||
try:
|
|
||||||
paginator.add_line(line)
|
|
||||||
except ValueError:
|
|
||||||
paginator.add_line(textwrap.shorten(line, width=1900, placeholder="<...>"))
|
|
||||||
|
|
||||||
if len(paginator.pages) > 1:
|
|
||||||
msg = None
|
|
||||||
if app.state.last_sender != body["sender"] or ts_diff >= 600:
|
|
||||||
msg = await channel.send(f"**{body['sender']}**:")
|
|
||||||
m = len(paginator.pages)
|
|
||||||
for n, page in enumerate(paginator.pages, 1):
|
|
||||||
await channel.send(
|
|
||||||
f"[{n}/{m}]\n>>> {page}",
|
|
||||||
allowed_mentions=discord.AllowedMentions.none(),
|
|
||||||
reference=msg,
|
|
||||||
silent=True,
|
|
||||||
suppress=n != m,
|
|
||||||
)
|
|
||||||
app.state.last_sender = body["sender"]
|
|
||||||
else:
|
|
||||||
content = f"**{body['sender']}**:\n>>> {body['message']}"
|
|
||||||
if app.state.last_sender == body["sender"] and ts_diff < 600:
|
|
||||||
content = f">>> {body['message']}"
|
|
||||||
await channel.send(content, allowed_mentions=discord.AllowedMentions.none(), silent=True, suppress=False)
|
|
||||||
app.state.last_sender = body["sender"]
|
|
||||||
app.state.last_sender_ts = now
|
|
||||||
return {"status": "ok", "pages": len(paginator.pages)}
|
|
||||||
|
|
||||||
|
|
||||||
@app.websocket("/bridge/recv")
|
|
||||||
async def bridge_recv(ws: WebSocket, secret: str = Header(None)):
|
|
||||||
await ws.accept()
|
|
||||||
log.info("Websocket %s:%s accepted.", ws.client.host, ws.client.port)
|
|
||||||
if secret != app.state.bot.http.token:
|
|
||||||
log.warning("Closing websocket %r, invalid secret.", ws.client.host)
|
|
||||||
raise WebSocketException(code=1008, reason="Invalid Secret")
|
|
||||||
if app.state.ws_connected.locked():
|
|
||||||
log.warning("Closing websocket %r, already connected." % ws)
|
|
||||||
raise WebSocketException(code=1008, reason="Already connected.")
|
|
||||||
queue: asyncio.Queue = app.state.bot.bridge_queue
|
|
||||||
|
|
||||||
async with app.state.ws_connected:
|
|
||||||
while True:
|
|
||||||
try:
|
|
||||||
await ws.send_json({"status": "ping"})
|
|
||||||
except (WebSocketDisconnect, WebSocketException):
|
|
||||||
log.info("Websocket %r disconnected.", ws)
|
|
||||||
break
|
|
||||||
|
|
||||||
try:
|
|
||||||
data = await asyncio.wait_for(queue.get(), timeout=5)
|
|
||||||
except asyncio.TimeoutError:
|
|
||||||
continue
|
|
||||||
|
|
||||||
try:
|
|
||||||
await ws.send_json(data)
|
|
||||||
log.debug("Sent data %r to websocket %r.", data, ws)
|
|
||||||
except (WebSocketDisconnect, WebSocketException):
|
|
||||||
log.info("Websocket %r disconnected." % ws)
|
|
||||||
break
|
|
||||||
finally:
|
|
||||||
queue.task_done()
|
|
Loading…
Reference in a new issue