Skip to content

Commit b0079eb

Browse files
Add webhook example
1 parent 66a9436 commit b0079eb

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed
Loading
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# HTTP Callbacks (a.k.a. Webhooks)
2+
![demo.gif](.github/demo.gif)
3+
4+
```bash
5+
pip install -r requirements.txt
6+
./main.py
7+
```
8+
9+
In this example we are creating a HTTP server that has two routes:
10+
1. `GET /` - triggers the creation of submission on Judge0
11+
2. `PUT /callback` - called by Judge0 once the submission is done
12+
13+
When you run the HTTP server you should visit `http://localhost:8000` and that will create a new submission on Judge0. This submission will have a `callback_url` attribute set which Judge0 will call `PUT` HTTP verb once the submission is done.
14+
15+
For this to work the `callback_url` must be publicly accessible, so in this example we are using a free service https://localhost.run that allows us to expose your local HTTP server and make it available on the internet and accessible by Judge0.
16+
17+
Once the submission is done Judge0 will call our second route `PUT /callback` and in your terminal you should see the result.
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/env python3
2+
from fastapi import FastAPI, Depends
3+
from pydantic import BaseModel
4+
5+
import uvicorn
6+
import asyncio
7+
import judge0
8+
9+
10+
class CallbackResponse(BaseModel):
11+
created_at: str
12+
finished_at: str
13+
language: dict
14+
status: dict
15+
stdout: str
16+
17+
18+
class AppContext:
19+
def __init__(self):
20+
self.public_url = ""
21+
22+
23+
LOCAL_SERVER_PORT = 8000
24+
25+
app = FastAPI()
26+
app_context = AppContext()
27+
28+
29+
def get_app_context():
30+
return app_context
31+
32+
33+
@app.get("/")
34+
async def root(app_context=Depends(get_app_context)):
35+
if not app_context.public_url:
36+
return {
37+
"message": "Public URL is not available yet. Try again after a few seconds."
38+
}
39+
40+
submission = judge0.Submission(
41+
source_code="print('Hello, World!')",
42+
language_id=judge0.PYTHON,
43+
callback_url=f"{app_context.public_url}/callback",
44+
)
45+
46+
return judge0.async_execute(submissions=submission)
47+
48+
49+
@app.put("/callback")
50+
async def callback(response: CallbackResponse):
51+
print(f"Received: {response}")
52+
53+
54+
# We are using free service from https://localhost.run to get a public URL for our local server.
55+
# This approach is not recommended for production use. It is only for demonstration purposes
56+
# since domain names change regularly and there is a speed limit for the free service.
57+
async def run_ssh_tunnel():
58+
app_context = get_app_context()
59+
60+
command = [
61+
"ssh",
62+
"-o",
63+
"StrictHostKeyChecking=no",
64+
"-o",
65+
"ServerAliveInterval=30",
66+
"-R",
67+
f"80:localhost:{LOCAL_SERVER_PORT}",
68+
"localhost.run",
69+
]
70+
71+
process = await asyncio.create_subprocess_exec(
72+
*command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.STDOUT
73+
)
74+
75+
while True:
76+
line = await process.stdout.readline()
77+
if not line:
78+
break
79+
80+
decoded_line = line.decode().strip()
81+
if decoded_line.endswith(".lhr.life"):
82+
app_context.public_url = decoded_line.split()[-1].strip()
83+
84+
await process.wait()
85+
86+
87+
async def run_server():
88+
config = uvicorn.Config(
89+
app, host="127.0.0.1", port=LOCAL_SERVER_PORT, workers=5, loop="asyncio"
90+
)
91+
server = uvicorn.Server(config)
92+
await server.serve()
93+
94+
95+
async def main():
96+
await asyncio.gather(run_ssh_tunnel(), run_server())
97+
98+
99+
if __name__ == "__main__":
100+
asyncio.run(main())
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
fastapi==0.115.4
2+
uvicorn==0.32.0

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy