d3c914285c
Build and Push Docker Container / build-and-push (push) Successful in 2m3s
- Add a private SSE endpoint that emits file change events for authenticated clients. - Replace the watch sleep loop with watchdog local file events and remote SSE triggers. - Debounce local event bursts and keep watch running after transient sync failures. - Add watchdog as a standalone CLI dependency and cover watch behavior in tests. - Bump NanoShare to 1.25.0 and the standalone CLI to 0.4.0.
52 lines
1.6 KiB
Python
52 lines
1.6 KiB
Python
from __future__ import annotations
|
|
|
|
import asyncio
|
|
import json
|
|
|
|
from my_modules.app.setup import LIMITER
|
|
from my_modules.decoratory.header import token_required
|
|
from quart import Blueprint, Response, current_app, stream_with_context
|
|
|
|
api_events_bp = Blueprint('api_events', __name__)
|
|
|
|
async def _snapshot(user_id: str) -> str:
|
|
files = await current_app.convex.get_files(user_id)
|
|
rows = []
|
|
for item in files or []:
|
|
if not isinstance(item, dict):
|
|
continue
|
|
rows.append({
|
|
'file_id': item.get('file_id'),
|
|
'file_name': item.get('file_name'),
|
|
'file_path': item.get('file_path') or '',
|
|
'file_size': item.get('file_size'),
|
|
'expires_at': item.get('expires_at'),
|
|
'updated_at': item.get('updated_at') or item.get('uploaded_at'),
|
|
})
|
|
rows.sort(key=lambda row: str(row.get('file_id') or ''))
|
|
return json.dumps(rows, sort_keys=True, separators=(',', ':'))
|
|
|
|
@api_events_bp.get('/api/files/events')
|
|
@LIMITER.limit('6 per minute;60 per hour;')
|
|
@token_required(['files', 'mesh'])
|
|
async def api_file_events(user: dict):
|
|
user_id = user['sub']
|
|
|
|
@stream_with_context
|
|
async def stream():
|
|
previous = await _snapshot(user_id)
|
|
yield 'event: ready\ndata: {}\n\n'
|
|
while True:
|
|
await asyncio.sleep(30)
|
|
current = await _snapshot(user_id)
|
|
if current != previous:
|
|
previous = current
|
|
yield f'event: files.changed\ndata: {current}\n\n'
|
|
else:
|
|
yield ': keepalive\n\n'
|
|
|
|
return Response(stream(), content_type='text/event-stream', headers={
|
|
'Cache-Control': 'no-cache',
|
|
'X-Accel-Buffering': 'no',
|
|
})
|