feat(updates): check Gitea automatically and deploy on owner confirmation

Add owner-only update controls, a read-only SSH checker and independent systemd deployment services. Build before maintenance; back up code and database; restore on failed deployment. Preserve runtime configuration and gate business writes during the switch.
This commit is contained in:
WangShen007 committed 2026-10-24 07:26:41 +00:00
1 parent 9b5463ecb3
commit e2bafd8bff
28 files changed
+1346 -1

No files matched your search

+30
View File
@@ -0,0 +1,30 @@
"""Gate business traffic during deployment and database recovery, including sockets."""
import asyncio
from pathlib import Path
from starlette.types import ASGIApp, Receive, Scope, Send
from starlette.responses import JSONResponse
MAINTENANCE_FILE = Path('/var/lib/replypier-updater/maintenance')
class SystemMaintenanceMiddleware:
def __init__(self, app: ASGIApp) -> None:
self.app = app
async def __call__(self, scope: Scope, receive: Receive, send: Send) -> None:
path = scope.get('path', '')
exempt = path == '/health' or (path == '/api/v1/system-updates' and scope.get('method') == 'GET')
if scope['type'] in {'http', 'websocket'} and MAINTENANCE_FILE.exists() and not exempt:
if scope['type'] == 'websocket':
await send({'type': 'websocket.close', 'code': 1013})
else:
response = JSONResponse({'detail': '系统更新中,接待将在更新完成后恢复。'},
status_code=503, headers={'Retry-After': '5'})
await response(scope, receive, send)
return
await self.app(scope, receive, send)
async def wait_for_deployment() -> None:
while MAINTENANCE_FILE.exists():
await asyncio.sleep(1)