add proxy app to repo
Signed-off-by: disqualifier <dev@disqualifier.me>
This commit is contained in:
parent
030109c08b
commit
fbe66b1473
111
app.py
Normal file
111
app.py
Normal file
@ -0,0 +1,111 @@
|
||||
"""
|
||||
discord webhook reformat proxy
|
||||
|
||||
drop-in for discord.com: swap the hostname on a gitea (discord-type) webhook
|
||||
so it points here, e.g.
|
||||
https://discord.com/api/webhooks/<id>/<token>
|
||||
becomes
|
||||
https://proxy.example.com/api/webhooks/<id>/<token>
|
||||
|
||||
the proxy receives gitea's native discord embed, rewrites only the embed
|
||||
`description` into github's `[`hash`](url)` backtick style (hash backticked,
|
||||
commit message collapsed to its first line, author kept), and forwards the
|
||||
otherwise-untouched payload to the real discord webhook. everything gitea
|
||||
already handled (title, branches, multiple commits, tags, colors) passes
|
||||
through as-is.
|
||||
|
||||
run:
|
||||
pip install fastapi httpx uvicorn
|
||||
uvicorn discord_reformat_proxy:app --host 127.0.0.1 --port 8000
|
||||
|
||||
then set a gitea webhook (type: discord) to:
|
||||
http://127.0.0.1:8000/api/webhooks/<id>/<token>
|
||||
"""
|
||||
|
||||
import re
|
||||
import logging
|
||||
|
||||
import httpx
|
||||
from fastapi import FastAPI, Request, Response
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
app = FastAPI()
|
||||
|
||||
DISCORD_BASE = "https://discord.com"
|
||||
TIMEOUT = 10
|
||||
|
||||
# gitea commit line: [hash](url) <message possibly spanning lines> - author
|
||||
# github commit line: [`hash`](url) <first line of message> - author
|
||||
# match a hash-link, then the message up to an optional trailing " - author",
|
||||
# stopping at the next commit line or end of string.
|
||||
_COMMIT = re.compile(
|
||||
r"\[`?([0-9a-f]{6,40})`?\]\((https?://[^)]+)\)"
|
||||
r"\s+(.*?)"
|
||||
r"(\s-\s[^\n]+?)?"
|
||||
r"(?=\n\[|\Z)",
|
||||
re.DOTALL,
|
||||
)
|
||||
|
||||
|
||||
def _commit_sub(m: "re.Match") -> str:
|
||||
"""rebuild one commit line github-style: backtick hash, first message line only"""
|
||||
short, url, message, author = m.group(1), m.group(2), m.group(3), m.group(4) or ""
|
||||
first_line = message.strip().split("\n", 1)[0].strip()
|
||||
return f"[`{short}`]({url}) {first_line}{author}"
|
||||
|
||||
|
||||
def _reformat(description: str) -> str:
|
||||
"""rewrite gitea commit lines into github-style (backtick hash, one line each)"""
|
||||
return _COMMIT.sub(_commit_sub, description)
|
||||
|
||||
|
||||
@app.get("/healthz")
|
||||
async def healthz():
|
||||
"""liveness probe"""
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@app.post("/api/webhooks/{webhook_id}/{token}")
|
||||
async def proxy(webhook_id: str, token: str, request: Request):
|
||||
"""reformat embed descriptions and forward to the real discord webhook"""
|
||||
try:
|
||||
payload = await request.json()
|
||||
except Exception:
|
||||
body = await request.body()
|
||||
async with httpx.AsyncClient(timeout=TIMEOUT) as client:
|
||||
resp = await client.post(
|
||||
f"{DISCORD_BASE}/api/webhooks/{webhook_id}/{token}",
|
||||
content=body,
|
||||
params=dict(request.query_params),
|
||||
headers={"content-type": request.headers.get("content-type", "application/json")},
|
||||
)
|
||||
return _passthrough(resp)
|
||||
|
||||
if isinstance(payload, dict):
|
||||
for embed in payload.get("embeds") or []:
|
||||
if isinstance(embed, dict) and embed.get("description"):
|
||||
embed["description"] = _reformat(embed["description"])
|
||||
|
||||
async with httpx.AsyncClient(timeout=TIMEOUT) as client:
|
||||
resp = await client.post(
|
||||
f"{DISCORD_BASE}/api/webhooks/{webhook_id}/{token}",
|
||||
json=payload,
|
||||
params=dict(request.query_params),
|
||||
)
|
||||
|
||||
return _passthrough(resp)
|
||||
|
||||
|
||||
def _passthrough(resp: httpx.Response) -> Response:
|
||||
"""return discord's response verbatim, preserving rate-limit headers"""
|
||||
forward = {
|
||||
k: v for k, v in resp.headers.items()
|
||||
if k.lower().startswith("x-ratelimit") or k.lower() == "retry-after"
|
||||
}
|
||||
return Response(
|
||||
content=resp.content,
|
||||
status_code=resp.status_code,
|
||||
media_type=resp.headers.get("content-type"),
|
||||
headers=forward,
|
||||
)
|
||||
Loading…
Reference in New Issue
Block a user