name: lobster-ai

services:
  lobster-code-sandbox-docker:
    image: docker:26-dind
    container_name: lobster-code-sandbox-docker
    privileged: true
    environment:
      DOCKER_TLS_CERTDIR: ""
      TZ: Asia/Shanghai
    command:
      - dockerd
      - --host=tcp://0.0.0.0:2375
      - --host=unix:///var/run/docker.sock
      - --registry-mirror=https://docker.m.daocloud.io
      - --registry-mirror=https://docker.1ms.run
    volumes:
      - lobster-code-sandbox-docker-data:/var/lib/docker
      - lobster-code-sandbox-work:/srv/sandbox
      - lobster-code-sandbox-bundles:/var/cache/lobster/skill-bundles
    healthcheck:
      test: ["CMD", "docker", "info"]
      interval: 10s
      timeout: 5s
      retries: 30

  lobster-code-sandbox-builder:
    image: docker:26-cli
    container_name: lobster-code-sandbox-builder
    profiles: ["build"]
    depends_on:
      lobster-code-sandbox-docker:
        condition: service_healthy
    environment:
      DOCKER_HOST: tcp://lobster-code-sandbox-docker:2375
    working_dir: /work
    volumes:
      - /home/app/lobster-ai/zm-ai-server/WEB-INF/lobster/deploy:/deploy:ro
      - /home/app/lobster-ai/zm-ai-server/WEB-INF/fonts:/fonts:ro
      - /home/app/lobster-ai/zm-ai-server/WEB-INF/lobster:/lobster-webinf
    command:
      - sh
      - -lc
      - |
        set -eu
        apk add --no-cache python3 >/dev/null
        rm -rf /tmp/lobster-sandbox-build
        mkdir -p /tmp/lobster-sandbox-build
        cp -a /deploy/. /tmp/lobster-sandbox-build/
        cp -a /fonts /tmp/lobster-sandbox-build/fonts
        python3 - <<'PY'
        from pathlib import Path
        from textwrap import dedent
        import re
        path = Path('/tmp/lobster-sandbox-build/sandbox/Dockerfile')
        text = path.read_text(encoding='utf-8')
        text = text.replace(
            'RUN apt-get update && apt-get install -y --no-install-recommends',
            "RUN sed -i 's|deb.debian.org|mirrors.aliyun.com|g; s|security.debian.org|mirrors.aliyun.com|g' /etc/apt/sources.list /etc/apt/sources.list.d/*.sources 2>/dev/null || true\n"
            'RUN apt-get update && apt-get install -y --no-install-recommends',
            1,
        )
        text = text.replace(
            'RUN pip install --no-cache-dir',
            'RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple --trusted-host pypi.tuna.tsinghua.edu.cn',
            1,
        )
        npm_replacement = dedent("""\
        RUN npm config set registry https://registry.npmmirror.com \\
            && npm config set fetch-retries 5 \\
            && npm config set fetch-retry-mintimeout 20000 \\
            && npm config set fetch-retry-maxtimeout 120000 \\
            && npm config set fetch-timeout 120000
        COPY --from=lobster-sandbox:py3.11-office-v4-nodebase /usr/lib/node_modules /usr/lib/node_modules
        RUN printf '%s\\\\n' '#!/bin/sh' 'exec node /usr/lib/node_modules/pnpm/bin/pnpm.cjs "$@"' > /usr/bin/pnpm \\
            && printf '%s\\\\n' '#!/bin/sh' 'exec node /usr/lib/node_modules/pnpm/bin/pnpx.cjs "$@"' > /usr/bin/pnpx \\
            && printf '%s\\\\n' '#!/bin/sh' 'exec node /usr/lib/node_modules/parcel/lib/bin.js "$@"' > /usr/bin/parcel \\
            && printf '%s\\\\n' '#!/bin/sh' 'exec node /usr/lib/node_modules/html-inline/bin/cmd.js "$@"' > /usr/bin/html-inline \\
            && chmod +x /usr/bin/pnpm /usr/bin/pnpx /usr/bin/parcel /usr/bin/html-inline
        RUN npm install -g --omit=dev jszip@3.10.1 \\
            && npm cache clean --force""").strip()
        text, npm_replacements = re.subn(
            r'RUN npm install -g --omit=dev.*?&& npm cache clean --force',
            npm_replacement,
            text,
            count=1,
            flags=re.S,
        )
        if npm_replacements != 1:
            raise RuntimeError('Failed to replace npm global install block')
        text = text.replace(
            "RUN printf 'store-dir=/opt/pnpm-store\\nprefer-offline=true\\nauto-install-peers=true\\n' > /etc/pnpmrc",
            "RUN printf 'store-dir=/opt/pnpm-store\\nregistry=https://registry.npmmirror.com\\nprefer-offline=true\\nauto-install-peers=true\\n' > /etc/pnpmrc",
            1,
        )
        path.write_text(text, encoding='utf-8')
        PY
        docker build \
          -t lobster-sandbox:py3.11-office-v4 \
          -f /tmp/lobster-sandbox-build/sandbox/Dockerfile \
          /tmp/lobster-sandbox-build
        docker run --rm --entrypoint python lobster-sandbox:py3.11-office-v4 \
          -m pip list --format=json > /tmp/pip.json
        docker run --rm --entrypoint npm lobster-sandbox:py3.11-office-v4 \
          ls -g --depth=0 --json > /tmp/npm.json 2>/dev/null || true
        python3 - <<'PY' > /lobster-webinf/sandbox-installed-packages.json
        import json
        pip = json.load(open('/tmp/pip.json', encoding='utf-8'))
        try:
            npm_obj = json.load(open('/tmp/npm.json', encoding='utf-8'))
            npm = sorted((npm_obj.get('dependencies') or {}).keys())
        except Exception:
            npm = []
        print(json.dumps({
            "image": "lobster-sandbox:py3.11-office-v4",
            "packages": pip,
            "npm": npm,
        }, ensure_ascii=False, indent=2))
        PY


  lobster-ai-tomcat:
    build:
      context: .
      dockerfile: tomcat-docker-cli.Dockerfile
    container_name: lobster-ai-tomcat
    depends_on:
      lobster-code-sandbox-docker:
        condition: service_healthy
    environment:
      DOCKER_HOST: tcp://lobster-code-sandbox-docker:2375
      TZ: Asia/Shanghai
      JAVA_OPTS: >-
        -Dfile.encoding=UTF-8
        -Duser.timezone=Asia/Shanghai
        -Xms512m
        -Xmx2048m
    ports:
      - "8080:8080"
    volumes:
      - /home/app/lobster-ai/zm-ai-server:/usr/local/tomcat/webapps/ROOT
      - /home/app/lobster-ai/zm-ai-frontend/dist/build/ai-ui:/usr/local/tomcat/webapps/ROOT/ai-ui:ro
      - /home/app/lobster-ai/log:/log/zmeg_new
      - /home/app/lobster-ai/zm_new_files:/files1
      - lobster-ai-content:/home/app/lobster
      - lobster-code-sandbox-work:/srv/sandbox
      - lobster-code-sandbox-bundles:/var/cache/lobster/skill-bundles

  lobster-ai-frontend-build:
    image: node:20-bookworm
    container_name: lobster-ai-frontend-build
    profiles: ["build"]
    working_dir: /app
    volumes:
      - /home/app/lobster-ai/zm-ai-frontend:/app
      - lobster-ai-frontend-node-modules:/app/node_modules
    command:
      - sh
      - -lc
      - |
        set -eu
        corepack enable
        yarn install --frozen-lockfile
        yarn build-h5:custom

  lobster-ai-update-build:
    build:
      context: .
      dockerfile: update-builder.Dockerfile
    container_name: lobster-ai-update-build
    profiles: ["update"]
    working_dir: /home/app/lobster-ai/deploy/docker
    environment:
      BASE_DIR: /home/app/lobster-ai
      SOURCE_DIR: /home/app/lobster-ai/source-code
      DOCKER_DIR: /home/app/lobster-ai/deploy/docker
      WEBAPP_DIR: /home/app/lobster-ai/zm-ai-server
      FRONTEND_RUNTIME_DIR: /home/app/lobster-ai/zm-ai-frontend
      SERVER_REPO_URL: ${SERVER_REPO_URL:-http://192.168.1.204:3000/gzzm/zm-ai-server.git}
      SERVER_BRANCH: ${SERVER_BRANCH:-master}
      FRONTEND_REPO_URL: ${FRONTEND_REPO_URL:-http://192.168.1.204:3000/gzzm-frontend/ai-deepseek.git}
      FRONTEND_BRANCH: ${FRONTEND_BRANCH:-next}
    volumes:
      - /home/app/lobster-ai:/home/app/lobster-ai
      - /var/run/docker.sock:/var/run/docker.sock
      - /root/.gitconfig:/host-gitconfig:ro
      - /root/.git-credentials:/host-git-credentials:ro
      - lobster-ai-update-m2:/root/.m2
    command:
      - bash
      - -lc
      - |
        cp /host-gitconfig /root/.gitconfig
        cp /host-git-credentials /root/.git-credentials
        chmod 600 /root/.gitconfig /root/.git-credentials
        exec /home/app/lobster-ai/deploy/docker/update-build.sh

volumes:
  lobster-ai-content:
  lobster-code-sandbox-docker-data:
  lobster-code-sandbox-work:
  lobster-code-sandbox-bundles:
  lobster-ai-frontend-node-modules:
  lobster-ai-update-m2:
