from copy import deepcopy
import random
import string
import solara
import solara.lab
import solara.server.kernel_context
from starlette.responses import JSONResponse
from starlette.requests import Request
from anyio import to_thread
added = False
webhooks_result = solara.reactive(None)
def update_webhook_value(message):
# we update the reactive value for all kernels (i.e. connected browser pages)
for kernel_id, context in solara.server.kernel_context.contexts.items():
with context:
old_value = webhooks_result.value
message = deepcopy(message)
print(f'Updating webhook value from "{old_value}" to "{message}". Kernel: {kernel_id}')
webhooks_result.value = message
async def webhook_handler(request: Request):
try:
payload = await request.json()
print('Request received!')
print(payload.get('message', 'no message'))
payload = deepcopy(payload)
# if we call this directly, we run in the same thread as the uvicorn/starlette server (or anyio thread)
# that the websocket is related to, which causes issues (it will raise an exception in solara >= 1.43)
# using anyio, we run it in a separate thread
await to_thread.run_sync(update_webhook_value, payload.get('message', 'no message'))
return JSONResponse({
"status": "success",
"message": "Webhook received",
"data": payload
})
except Exception as e:
return JSONResponse({
"status": "error",
"message": str(e)
}, status_code=400)
def add_webhook_handler():
# workaround since we cannot import solara.server.starlette directly
global added
if not added:
import solara.server.starlette
solara.server.starlette.app.router.add_route("/webhook", webhook_handler, methods=["POST"])
added = True
@solara.component
def Page():
add_webhook_handler()
with solara.Column(align="center", style={"height": "100%", "justify-content": "center"}):
with solara.Card(style="width: 400px; margin: auto;"):
with solara.Column():
if webhooks_result.value is None:
solara.Markdown("No data yet")
else:
solara.Markdown(f'{webhooks_result.value}')