#!/usr/bin/env bash set -euo pipefail SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck source=scripts/common.sh source "$SCRIPT_DIR/common.sh" ROTATE_SECRET=0 if [[ "${1:-}" == "--rotate-secret" ]]; then ROTATE_SECRET=1 shift fi if [[ $# -gt 0 ]]; then ctms_fail "未知参数: $1(支持的参数仅有 --rotate-secret)" fi generate_random_hex() { local bytes="${1:-32}" if command -v openssl >/dev/null 2>&1; then openssl rand -hex "$bytes" return fi od -An -N "$bytes" -tx1 /dev/urandom | tr -d ' \n' } prepare_onlyoffice_environment() { local secret current_login_secret instance_id generated=0 secret="$(ctms_read_env_value ONLYOFFICE_JWT_SECRET || true)" current_login_secret="$(ctms_read_env_value JWT_SECRET_KEY || true)" instance_id="$(ctms_read_env_value ONLYOFFICE_INSTANCE_ID || true)" if [[ "$ROTATE_SECRET" -eq 1 || ${#secret} -lt 32 || "$secret" == "$current_login_secret" ]]; then secret="$(generate_random_hex 32)" ctms_upsert_env_value ONLYOFFICE_JWT_SECRET "$secret" generated=1 fi if [[ -z "$instance_id" ]]; then instance_id="ctms-dev-$(generate_random_hex 8)" ctms_upsert_env_value ONLYOFFICE_INSTANCE_ID "$instance_id" fi ctms_upsert_env_value ONLYOFFICE_ENABLED true ctms_upsert_env_value ONLYOFFICE_INTERNAL_URL http://onlyoffice ctms_upsert_env_value ONLYOFFICE_STORAGE_BASE_URL http://backend:8000 ctms_upsert_env_value ONLYOFFICE_CONFIG_TTL_SECONDS 300 chmod 600 "$CTMS_ENV_FILE" if [[ "$generated" -eq 1 ]]; then ctms_ok "已生成新的 ONLYOFFICE 开发密钥并写入 .env(内容不会回显)" else ctms_ok "已复用 .env 中现有的 ONLYOFFICE 开发密钥" fi ctms_ok "ONLYOFFICE 开发实例标识已就绪: $instance_id" } wait_for_url() { local label="$1" url="$2" attempts="${3:-90}" attempt=1 while [[ "$attempt" -le "$attempts" ]]; do if curl -fsS "$url" >/dev/null 2>&1; then ctms_ok "$label 已就绪" return 0 fi sleep 2 attempt=$(( attempt + 1 )) done ctms_fail "$label 未在预期时间内就绪: $url" } main() { cd "$CTMS_ROOT_DIR" ctms_require_docker_compose ctms_require_command curl "macOS 通常已预装;Linux 可执行 apt-get install curl" \ || ctms_fail "缺少 curl,无法执行启动健康检查" ctms_step "准备 ONLYOFFICE 开发环境" prepare_onlyoffice_environment local -a compose=( docker compose -f "$CTMS_ROOT_DIR/docker-compose.dev.yaml" -p ctms_dev ) ctms_step "校验开发 Compose 配置" "${compose[@]}" config --quiet ctms_ok "Compose 配置有效" ctms_step "重新构建并启动标准 ONLYOFFICE 服务" "${compose[@]}" up -d --build --force-recreate backend onlyoffice nginx ctms_step "验证运行状态" wait_for_url "CTMS 后端" "http://127.0.0.1:8888/readyz" 60 wait_for_url "ONLYOFFICE Document Server" "http://127.0.0.1:8888/onlyoffice/healthcheck" 120 "${compose[@]}" exec -T backend python -c ' from app.core.config import settings from app.main import app paths = {route.path for route in app.routes} required = { "/api/v1/onlyoffice/attachments/{attachment_id}/config", "/api/v1/onlyoffice/versions/{version_id}/config", "/api/v1/studies/{study_id}/collaboration/files/{file_id}/editor-config", "/api/v1/studies/{study_id}/collaboration/files/{file_id}/share-link", "/api/v1/collaboration/shares/metadata", "/api/v1/collaboration/shares/access", "/api/v1/collaboration/shares/editor-config", "/internal/onlyoffice/collaboration/sessions/{session_id}/content", "/internal/onlyoffice/collaboration/sessions/{session_id}/callback", } if not settings.ONLYOFFICE_ENABLED: raise SystemExit("ONLYOFFICE_ENABLED 未生效") if len(settings.ONLYOFFICE_JWT_SECRET or "") < 32: raise SystemExit("ONLYOFFICE_JWT_SECRET 未生效") if not settings.ONLYOFFICE_INSTANCE_ID: raise SystemExit("ONLYOFFICE_INSTANCE_ID 未生效") missing = required - paths if missing: raise SystemExit(f"后端缺少 ONLYOFFICE 路由: {sorted(missing)}") print("ONLYOFFICE backend configuration and routes are ready") ' ctms_ok "ONLYOFFICE 开发预览环境启动完成" } main