#!/bin/bash
##X86+ARM架构一体化部署脚本(不含会议+手动注册)
##用法: /bin/bash install-se.sh "访问地址" [http|https|reset_https|reset_hosts|reset_domain|uninstall|uninstall_data|update_service|部署记录ID]

##仅卸载部署数据模式: 删除容器和部署数据, 保留镜像和Docker网络
if [[ "$2" == "uninstall_data" ]]; then
    if [[ "$(id -u)" -ne 0 ]]; then
        echo "您必须登录到root用户环境才能执行数据卸载, 请登录成功后重试"
        exit 1
    fi

    SE_UNINSTALL_DATA_CONTAINERS=(
        "wp-server" "wp-http" "wp-dash" "wp-calendar" "wp-auditlog"
        "kunlun-dapr" "db-fdfs" "db-mongo" "db-mysql" "db-redis"
        "app-bpm" "app-form" "app-tsq" "app-html" "app-kaoqin" "app-sync"
        "app-document" "meet-api" "wp-nginx" "db-minio" "bpm-intermediary"
    )
    SE_UNINSTALL_DATA_FILES=(
        ".hostinfo" ".urlprefix" ".lanip" ".dirinfo" ".verinfo" ".loginfo"
        ".imssl" ".imtype" ".dbdriver" ".dbsetup" ".driver" ".reginfo" ".portlist" ".minioinfo"
    )

    echo "开始卸载 WorkPlus-SE 容器和部署数据"
    echo "删除脚本创建的容器、/root 下明确隐藏文件和 /home/workplus 下部署文件"
    echo "保留全部 Docker 镜像和 Docker 网络"

    if ! command -v docker >/dev/null 2>&1; then
        echo "未检测到docker命令, 跳过容器清理"
    else
        for container in "${SE_UNINSTALL_DATA_CONTAINERS[@]}"; do
            if docker container inspect "$container" >/dev/null 2>&1; then
                echo "删除容器: $container"
                docker rm -f "$container" >/dev/null 2>&1 || echo "警告: 删除容器失败: $container"
            fi
        done
    fi

    if [[ -d "/root" ]]; then
        for hidden_file in "${SE_UNINSTALL_DATA_FILES[@]}"; do
            if [[ -e "/root/$hidden_file" || -L "/root/$hidden_file" ]]; then
                echo "删除脚本配置文件: /root/$hidden_file"
                rm -f -- "/root/$hidden_file" || echo "警告: 删除文件失败: /root/$hidden_file"
            fi
        done
    else
        echo "未找到/root目录, 跳过root隐藏配置文件清理"
    fi

    if [[ -d "/home/workplus" ]]; then
        echo "删除部署目录内容: /home/workplus"
        find "/home/workplus" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} + || {
            echo "错误: 删除 /home/workplus 下部署文件失败"
            exit 1
        }
    else
        echo "未找到/home/workplus目录, 跳过部署数据清理"
    fi

    echo "WorkPlus-SE 容器和部署数据卸载完成"
    exit 0
fi

##卸载模式必须在部署初始化之前处理, 避免创建日志目录或执行安装前置检查
if [[ "$2" == "uninstall" ]]; then
    if [[ "$(id -u)" -ne 0 ]]; then
        echo "您必须登录到root用户环境才能执行卸载, 请登录成功后重试"
        exit 1
    fi

    SE_UNINSTALL_CONTAINERS=(
        "wp-server" "wp-http" "wp-dash" "wp-calendar" "wp-auditlog"
        "kunlun-dapr" "db-fdfs" "db-mongo" "db-mysql" "db-redis"
        "app-bpm" "app-form" "app-tsq" "app-html" "app-kaoqin" "app-sync"
        "app-document" "meet-api" "wp-nginx" "db-minio" "bpm-intermediary"
    )
    SE_UNINSTALL_IMAGES=(
        "swr.cn-south-1.myhuaweicloud.com/workplus/se-server"
        "swr.cn-south-1.myhuaweicloud.com/workplus/se-http"
        "swr.cn-south-1.myhuaweicloud.com/workplus/se-dash"
        "swr.cn-south-1.myhuaweicloud.com/workplus/se-calendar"
        "swr.cn-south-1.myhuaweicloud.com/workplus/se-auditlog"
        "swr.cn-south-1.myhuaweicloud.com/workplus/kunlun-dapr"
        "swr.cn-south-1.myhuaweicloud.com/workdbs/fastdfs"
        "swr.cn-south-1.myhuaweicloud.com/workdbs/mongo"
        "swr.cn-south-1.myhuaweicloud.com/workdbs/mysql"
        "swr.cn-south-1.myhuaweicloud.com/workdbs/redis"
        "swr.cn-south-1.myhuaweicloud.com/workapps/app-bpm"
        "swr.cn-south-1.myhuaweicloud.com/workapps/app-form"
        "swr.cn-south-1.myhuaweicloud.com/workapps/app-tsq"
        "swr.cn-south-1.myhuaweicloud.com/workapps/app-html"
        "swr.cn-south-1.myhuaweicloud.com/workapps/app-kaoqin"
        "swr.cn-south-1.myhuaweicloud.com/workapps/app-sync"
        "swr.cn-south-1.myhuaweicloud.com/workapps/documentserver-ce"
        "swr.cn-south-1.myhuaweicloud.com/workapps/meet-backend"
        "swr.cn-south-1.myhuaweicloud.com/workapps/nginx"
        "swr.cn-south-1.myhuaweicloud.com/workdbs/minio"
        "swr.cn-south-1.myhuaweicloud.com/workapps/bpm-intermediary"
    )
    SE_UNINSTALL_FILES=(
        ".hostinfo" ".urlprefix" ".lanip" ".dirinfo" ".verinfo" ".loginfo"
        ".imssl" ".imtype" ".dbdriver" ".dbsetup" ".driver" ".reginfo" ".portlist" ".minioinfo"
    )

    echo "开始卸载 WorkPlus-SE 部署资源"
    if ! command -v docker >/dev/null 2>&1; then
        echo "未检测到docker命令, 跳过容器和镜像清理"
    else
        for container in "${SE_UNINSTALL_CONTAINERS[@]}"; do
            if docker container inspect "$container" >/dev/null 2>&1; then
                echo "删除容器: $container"
                docker rm -f "$container" >/dev/null 2>&1 || echo "警告: 删除容器失败: $container"
            fi
        done
        for image in "${SE_UNINSTALL_IMAGES[@]}"; do
            image_refs=$(docker image ls "$image" --format '{{.Repository}}:{{.Tag}}' 2>/dev/null)
            if [[ -n "$image_refs" ]]; then
                while IFS= read -r image_ref; do
                    [[ -z "$image_ref" ]] && continue
                    echo "删除镜像: $image_ref"
                    docker image rm "$image_ref" >/dev/null 2>&1 || echo "警告: 删除镜像失败: $image_ref"
                done <<< "$image_refs"
            fi
        done
    fi

    if [[ -d "/root" ]]; then
        for hidden_file in "${SE_UNINSTALL_FILES[@]}"; do
            if [[ -e "/root/$hidden_file" || -L "/root/$hidden_file" ]]; then
                echo "删除脚本配置文件: /root/$hidden_file"
                rm -f -- "/root/$hidden_file" || echo "警告: 删除文件失败: /root/$hidden_file"
            fi
        done
    else
        echo "未找到/root目录, 跳过root隐藏配置文件清理"
    fi

    if [[ "/home/workplus" == "/home/workplus" && -d "/home/workplus" ]]; then
        echo "删除部署目录内容: /home/workplus"
        find "/home/workplus" -mindepth 1 -maxdepth 1 -exec rm -rf -- {} + || {
            echo "错误: 删除 /home/workplus 下部署文件失败"
            exit 1
        }
    fi
    echo "WorkPlus-SE 卸载完成"
    exit 0
fi

##获取服务器内网IP地址
##如下命令如果无法准确获取内网IP则请手动配置
LANIP=$(ip addr show $(ip route show default|awk '/default/{print $5}'|head -n 1)|awk '/inet /{print $2}'|cut -d'/' -f1|grep -v '127.0.0.1'|head -n 1)

if [[ -f ${HOME}/.hostinfo ]]; then
   HOST_GET=$(cat ${HOME}/.hostinfo)
else
   HOST_GET="${LANIP}"
fi

if [[ $# -lt 1 ]]; then
   if [ -z "${HOST_GET}" ];then
     echo -e "\033[1;31m
     访问地址(用于访问客户端和管理后台)参数为空, 安装中断退出;
     请在脚本后面传入访问地址(IP/域名)后再重新执行本脚本;
     安装方式: /bin/bash ./$(basename $0) \"IP或域名\";
     安装示例: /bin/bash ./$(basename $0) \"192.168.10.100\"
     卸载方式: /bin/bash ./$(basename $0) \"192.168.10.100\" \"uninstall\"
     \033[0m"
     exit 1;
   else
     echo -e "\033[1;31m
     访问地址(用于访问客户端和管理后台)参数为空, 安装中断退出;
     请在脚本后面传入访问地址(IP/域名)后再重新执行本脚本;
     安装方式: /bin/bash ./$(basename $0) \"IP或域名\"
     安装示例: /bin/bash ./$(basename $0) \"${HOST_GET}\"
     更新方式: /bin/bash ./$(basename $0) \"${HOST_GET}\" \"update_service\"
     \033[0m"
     exit 1;
   fi
fi

if [ -z "${LANIP}" ];then
   echo "无法获取本机有效内网IP地址, 请在下一步手动输入"
   read -ep "Unable to obtain a valid lan ip address, Please manually input: " lanipaddr
   if [[ "${lanipaddr}" == "127.0.0.1" ]] || [[ "${lanipaddr}" == "localhost" ]] || [[ "${lanipaddr}" == "10.0.0.1" ]] || [[ "${lanipaddr}" == "" ]];then
      echo -e "\n\033[1;31mPlease do not enter the ip address of the loop or null\033[0m\n"
      exit 1;
   else
     LANIP=${lanipaddr}
   fi
fi

HOST_INPUT=$1
SECOND_ARGS=$2
DEPLOY_RECORD_ID="$3"
UPDATE_SERVICE_MODE="false"
UPDATE_SERVICE_CONTAINER=""

# 无论第二参数是什么模式，先读取已保存的访问协议；文件不存在或为空时默认使用http
if [[ -s "${HOME}/.urlprefix" ]]; then
   URL_PREFIX=$(<"${HOME}/.urlprefix")
else
   URL_PREFIX=http
fi

if [[ -n "${SECOND_ARGS}" ]]; then
   other_args=${SECOND_ARGS}
   case "${other_args}" in
       http)
           URL_PREFIX=http
       ;;
       https)
           URL_PREFIX=https
       ;;
       reset_https)
           ##更新访问协议https
           URL_PREFIX=https
           reset_https='true'
       ;;
       reset_hosts)
           ##更新平台访问地址, 访问协议不变
           reset_hosts='true'
       ;;
       reset_domain)
           ##格式化平台
           reset_domain='true'
       ;;
       uninstall)
           echo "uninstall模式已在脚本前置流程处理"
           exit 1
       ;;
       uninstall_data)
           echo "uninstall_data模式已在脚本前置流程处理"
           exit 1
       ;;
       update_service)
           UPDATE_SERVICE_MODE="true"
       ;;
       *)
           if [[ "${other_args}" =~ ^[A-Za-z0-9-]{8,64}$ ]]; then
               DEPLOY_RECORD_ID="${other_args}"
           else
   echo -e "第2个参数无法识别, 第2个参数支持如下配置: \n1. 可留空不配, 默认平台访问协议为http;\n2. 输入https, 设置平台访问协议为https;\n3. 输入reset_https, 重新设置访问协议为https;\n4. 输入reset_hosts, 重新设置平台访问地址;\n5. 输入reset_domain, 重新格式化平台;\n6. 输入uninstall, 卸载脚本创建的容器、镜像和部署文件;\n7. 输入uninstall_data, 删除容器和部署文件但保留镜像;\n8. 输入update_service, 选择一个服务删除容器和镜像后重新安装（不含db-fdfs）;\n9. 输入部署记录ID, 用于部署结果回写;"
               exit 1;
           fi
       ;;
   esac
fi

if [[ "${URL_PREFIX}" != "http" && "${URL_PREFIX}" != "https" ]]; then
    URL_PREFIX=http
fi

MACH=`uname -m`
if [[ "${MACH}" == "x86_64" ]]; then
   echo "检测到本机为x86_64芯片架构, 使用x86_64分支部署"
   sleep 2
   ARCH=
   MYSQL_IMAGE_TAG="5.7.44"
fi

if [[ "${MACH}" == "aarch64" ]]; then
   echo "检测到本机为aarch64芯片架构, 使用aarch64分支部署"
   sleep 2
   ARCH='-arm64'
   MYSQL_IMAGE_TAG="8.0.39-arm64"
fi

if [[ "${MACH}" != "x86_64" && "${MACH}" != "aarch64" ]] ; then
   echo -e "\033[1;31m
   检测到本机为${MACH}芯片架构, 暂不支持该架构部署
   请使用x86_64或aarch64芯片架构的服务器再尝试部署
   \033[0m"
   exit 1;
fi

DIST="";
REV="";
KERNEL="";

CORE_REQUIREMENTS='4';
DISK_REQUIREMENTS='30';
MEMORY_REQUIREMENTS='15000';
#MEMORY_REMAINING='10485760';
ATTIME=$(date +%s);
XIAOMI_PUSH='103325'   ##WP-SE Channel ID
#XIAOMI_PUSH='142871'  ##BW-SE Channel ID
HUAWEI_PUSH='IM'

## 脚本所在目录及离线资源目录 (temp_files 与脚本同级)
SCRIPT_DIR=$(cd "$(dirname "$0")" 2>/dev/null && pwd || echo "$(pwd)")
OFFLINE_DIR="${SCRIPT_DIR}/temp_files"

WP_LOG=WARNING
WP_DIR="/home/workplus"
WP_VERSION="7.3.0${ARCH}"
DB_VERSION="7.3.0"
KUNLUN_VERSION="2.0.11${ARCH}"
#WP_HOST='127.0.0.1'
WP_SERVER_CONTAINER_NAME="wp-server";
WP_SERVER_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workplus/se-server";
WP_HTTP_CONTAINER_NAME="wp-http";
WP_HTTP_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workplus/se-http";
WP_DASH_CONTAINER_NAME="wp-dash";
WP_DASH_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workplus/se-dash";
WP_CALENDAR_CONTAINER_NAME="wp-calendar";
WP_CALENDAR_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workplus/se-calendar";
WP_AUDITLOG_CONTAINER_NAME="wp-auditlog";
WP_AUDITLOG_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workplus/se-auditlog";
KUNLUN_DAPR_CONTAINER_NAME="kunlun-dapr";
KUNLUN_DAPR_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workplus/kunlun-dapr";

FASTDFS_CONTAINER_NAME="db-fdfs";
FASTDFS_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workdbs/fastdfs";
FASTDFS_IMAGE_TAG="6.06${ARCH}"

MONGO_CONTAINER_NAME="db-mongo";
MONGO_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workdbs/mongo"
MONGO_IMAGE_TAG="4.2.18${ARCH}"
MONGO_USER="workplus"
MONGO_PASS="workplus"
MONGO_DATABASE="workplus"

##核心数据库驱动
CORE_DATABASE_DRIVER='mysql'

##默认mysql实例
MYSQL_CONTAINER_NAME="db-mysql";
MYSQL_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workdbs/mysql";
#MYSQL_IMAGE_TAG="8.0.39"
MYSQL_USER="workplus"
MYSQL_PASS="workplus"
MYSQL_DATABASE="wp_services"
MYSQL_ROOT_PASSWORD="WorkPlus#Root"

##第三方数据库(代替MySQL),支持神通/达梦
OTH_DATABASE_HOST='172.16.1.10'
OTH_DATABASE_PORT='5236'
OTH_DATABASE_USER='SYSDBA'
OTH_DATABASE_PASS='Abcd1234'
OTH_DATABASE_SERVICES='WP_SERVICES'
OTH_DATABASE_SERVICES_JOBS='WP_SERVICES_JOBS'
OTH_DATABASE_AUDITLOG='WP_AUDITLOG'
OTH_DATABASE_AUDITLOG_JOBS='WP_AUDITLOG_JOBS'
OTH_DATABASE_CALENDAR='WP_CALENDAR'
OTH_DATABASE_CALENDAR_JOBS='WP_CALENDAR_JOBS'

##神通数据库实例名
OTH_SHENTONG_INSTANCE='OSRDB'

REDIS_CONTAINER_NAME="db-redis";
REDIS_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workdbs/redis";
REDIS_IMAGE_TAG="6.2.10${ARCH}"

APP_BPM_CONTAINER_NAME="app-bpm"
APP_BPM_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/app-bpm"
APP_BPM_IMAGE_TAG="2.6.7${ARCH}"
APP_BPM_DB_VERSION="2.6.7"
APP_FORM_CONTAINER_NAME="app-form"
APP_FORM_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/app-form"
APP_FORM_IMAGE_TAG="2.6.8${ARCH}"
APP_TSQ_CONTAINER_NAME="app-tsq"
APP_TSQ_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/app-tsq"
APP_TSQ_IMAGE_TAG="1.0.0${ARCH}"
APP_HTML_CONTAINER_NAME="app-html"
APP_HTML_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/app-html"
APP_HTML_IMAGE_TAG="2.6.5${ARCH}"
APP_KAOQIN_CONTAINER_NAME="app-kaoqin"
APP_KAOQIN_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/app-kaoqin"
APP_KAOQIN_IMAGE_TAG="2.0.0${ARCH}"
APP_SYNC_CONTAINER_NAME="app-sync"
APP_SYNC_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/app-sync"
APP_SYNC_IMAGE_TAG="2.2.1${ARCH}"
DOCUMENT_CONTAINER_NAME="app-document"
DOCUMENT_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/documentserver-ce"
DOCUMENT_IMAGE_TAG="9.4.0${ARCH}"
MEETAPI_CONTAINER_NAME="meet-api"
MEETAPI_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/meet-backend"
MEETAPI_IMAGE_TAG="1.3.4${ARCH}"
MEETAPI_DATABASE="wp_services_meet"
MEETAPI_PORT="7011"
APP_PREVIEW_CONTAINER_NAME="app-preview"
APP_PREVIEW_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/kkfileview"
APP_PREVIEW_IMAGE_TAG="5.0.0${ARCH}"
APP_COLLABORA_CONTAINER_NAME="app-collabora"
APP_COLLABORA_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workplus/collabora"
APP_COLLABORA_IMAGE_TAG="1.0.0${ARCH}"
COLLABORA_HOST_PORT="9982"
COLLABORA_CONTAINER_PORT="9980"

NGINX_CONTAINER_NAME="wp-nginx"
NGINX_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/nginx"
NGINX_IMAGE_TAG="1.25.1${ARCH}"

MINIO_CONTAINER_NAME="db-minio"
MINIO_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workdbs/minio"
MINIO_IMAGE_TAG="v202308${ARCH}"

BPM_INTERMEDIARY_CONTAINER_NAME="bpm-intermediary"
BPM_INTERMEDIARY_IMAGE_NAME="swr.cn-south-1.myhuaweicloud.com/workapps/bpm-intermediary"
BPM_INTERMEDIARY_IMAGE_TAG="1.0.0${ARCH}"

DOCKER_BINARY_VERSION="27.3.1"
DOCKER_BINARY_AMD64="https://w6s-binaries.oss-cn-hangzhou.aliyuncs.com/software/docker-${DOCKER_BINARY_VERSION}-amd64.tgz"
DOCKER_BINARY_ARM64="https://w6s-binaries.oss-cn-hangzhou.aliyuncs.com/software/docker-${DOCKER_BINARY_VERSION}-arm64.tgz"

#IDC_URL="https://idcapi-dev.workplus.io"
IDC_URL="https://idcapi.beeworks.cn"

##Docker虚拟网络配置
##docker0网桥: 10.200.201.0/24 (通过daemon.json的bip配置)
##workplus自定义网络: 10.200.202.0/24
platform_name="workplus"
platform_subnet='10.200.202.0/24'

platform_msg_log="${WP_DIR}/logs/install.log"
platform_err_log="${WP_DIR}/logs/error.log"
platform_pro_log="${WP_DIR}/logs/process.log"
mkdir -p ${WP_DIR}/logs > /dev/null 2>&1
echo "$(date +%Y%m%d-%H:%M:%S)开始记录安装过程日志" > ${platform_msg_log} 2>&1
echo "$(date +%Y%m%d-%H:%M:%S)记录服务器系统信息开始" > ${platform_err_log} 2>&1
echo "服务器系统版本:" >> ${platform_err_log} 2>&1
cat /etc/os-release >> ${platform_err_log} 2>&1
echo "服务器内核版本:" >> ${platform_err_log} 2>&1
uname -a >> ${platform_err_log} 2>&1
echo "服务器芯片型号:" >> ${platform_err_log} 2>&1
cat /proc/cpuinfo|grep 'model name' >> ${platform_err_log} 2>&1
echo "服务器磁盘分区:" >> ${platform_err_log} 2>&1
df -h|grep -vE "boot|overlay" >> ${platform_err_log} 2>&1
echo "服务器内存使用:" >> ${platform_err_log} 2>&1
free -m >> ${platform_err_log} 2>&1
echo "服务器默认路由:" >> ${platform_err_log} 2>&1
ip route show default >> ${platform_err_log} 2>&1
echo "配置地址: ${URL_PREFIX}://${HOST_INPUT}" >> ${platform_msg_log} 2>&1
echo "配置地址: ${URL_PREFIX}://${HOST_INPUT}" >> ${platform_err_log} 2>&1
echo "$(date +%Y%m%d-%H:%M:%S)记录服务器系统信息结束" >> ${platform_err_log} 2>&1

platform_callback_log="${WP_DIR}/logs/callback-se.log"
platform_webhook_log="${WP_DIR}/logs/webhook-se.log"
CALLBACK_SENT="false"
WEBHOOK_SENT="false"
CALLBACK_ENABLED="true"
#SUCCESS_CALLBACK_ENABLED=false
SUCCESS_CALLBACK_ENABLED="${SUCCESS_CALLBACK_ENABLED:-true}"
IDC_CALLBACK_TOKEN="baf3e067c46b464f95aecff84f994712"
if [[ -z "${IDC_CALLBACK_URL}" ]]; then
    if [[ "${MODE}" == "test" ]]; then
        IDC_CALLBACK_URL="https://idcapi-dev.workplus.io/v1/deploy/record/pipeline-result"
    else
        IDC_CALLBACK_URL="https://idcapi.beeworks.cn/v1/deploy/record/pipeline-result"
    fi
fi
if [[ -z "${BOT_WEBHOOK_URL}" ]]; then
    if [[ "${MODE}" == "test" ]]; then
        BOT_WEBHOOK_URL="https://api.beeworks.cn/v1/bots/webhooks/c0aa03YTU5ODMzNzRmN2ZmZWE3MDkyM2UyYzQwOGRhNmYd29ya3BsdXM6MDE5"
    else
        BOT_WEBHOOK_URL="https://api.beeworks.cn/v1/bots/webhooks/a7f826OGFjYWE3MzEwN2IxZGJhNmQyYzY4YjY1YTgyMDEd29ya3BsdXM6MDE5"
    fi
fi

callback_command_exists() {
    type "$1" >/dev/null 2>&1
}

read_file_safe() {
    local file_path="$1"
    [[ -f "${file_path}" ]] && cat "${file_path}"
}

send_bot_deploy_result() {
    local record_status="$1"
    local result_message="$2"
    local diagnosis_log="$3"

    [[ "${IS_FRESH_DEPLOY}" != "true" ]] && return
    [[ "${WEBHOOK_SENT}" == "true" ]] && return
    if ! callback_command_exists curl || ! callback_command_exists jq; then
        echo "$(date +%Y%m%d-%H:%M:%S) skip webhook: curl or jq command missing" >>"${platform_webhook_log}" 2>&1
        return
    fi

    local service_schema="${URL_PREFIX:-http}"
    local service_public_host="${WP_HOST:-${HOST_INPUT}}"
    local admin_url="${service_schema}://${service_public_host}:${DASH_PORT:-9910}"
    local status_text="部署成功"
    local status_color="green"
    [[ "${record_status}" != "success" ]] && status_text="部署失败" && status_color="red"
    local data
    data=$(jq -n \
        --arg title "WorkPlus-SE部署结果通知" \
        --arg deploy_record_id "${DEPLOY_RECORD_ID}" \
        --arg server_address "${service_public_host}" \
        --arg admin_url "${admin_url}" \
        --arg status_text "${status_text}" \
        --arg status_color "${status_color}" \
        --arg result_message "${result_message}" \
        --arg diagnosis "${diagnosis_log}" \
        '{type:"rich_text",body:{content:({content:[
          [{tag:"text",text:$title}],
          [{tag:"text",text:"产品线：",style:{color:"grey"}},{tag:"text",text:"WorkPlus SE"}],
          [{tag:"text",text:"部署记录ID：",style:{color:"grey"}},{tag:"text",text:$deploy_record_id}],
          [{tag:"text",text:"服务器地址：",style:{color:"grey"}},{tag:"text",text:$server_address}],
          [{tag:"text",text:"管理后台：",style:{color:"grey"}},{tag:"text",text:$admin_url}],
          [{tag:"text",text:"部署结果：",style:{color:"grey"}},{tag:"text",text:$status_text,style:{color:$status_color}}],
          [{tag:"text",text:"结果说明：",style:{color:"grey"}},{tag:"text",text:$result_message}],
          [{tag:"text",text:"诊断信息：",style:{color:"grey"}},{tag:"text",text:$diagnosis}]
        ]}|tostring)}}')
    local webhook_url="${BOT_WEBHOOK_URL}"
    local response
    response=$(curl --silent --show-error --connect-timeout 10 --request POST \
        --url "${webhook_url}" --header 'Content-Type: application/json' --data "${data}" 2>&1)
    local exit_code=$?
    WEBHOOK_SENT="true"
    {
        echo "[$(date +%Y%m%d-%H:%M:%S)] se webhook request"
        echo "url: ${webhook_url}"
        echo "exit_code: ${exit_code}"
        echo "response: ${response}"
        echo ""
    } >>"${platform_webhook_log}" 2>&1
}

sync_deploy_result() {
    local record_status="$1"
    local result_message="$2"
    local raw_log="$3"
    local diagnosis_log="$4"

    [[ "${IS_FRESH_DEPLOY}" != "true" ]] && return
    send_bot_deploy_result "${record_status}" "${result_message}" "${diagnosis_log}"
    [[ "${CALLBACK_SENT}" == "true" ]] && return
    if [[ -z "${DEPLOY_RECORD_ID}" ]]; then
        echo "$(date +%Y%m%d-%H:%M:%S) skip callback: DEPLOY_RECORD_ID is empty" >>"${platform_callback_log}" 2>&1
        return
    fi
    if ! callback_command_exists curl || ! callback_command_exists jq; then
        echo "$(date +%Y%m%d-%H:%M:%S) skip callback: curl or jq command missing" >>"${platform_callback_log}" 2>&1
        return
    fi

    local provider="self-hosted-se-x86_64"
    [[ "${MACH}" == "aarch64" ]] && provider="self-hosted-se-arm64"
    local service_schema="${URL_PREFIX:-http}"
    local service_public_host="${WP_HOST:-${HOST_INPUT}}"
    local admin_url="${service_schema}://${service_public_host}:${DASH_PORT:-9910}"
    local payload
    payload=$(jq -n \
        --arg deploy_record_id "${DEPLOY_RECORD_ID}" \
        --arg record_status "${record_status}" \
        --arg provider "${provider}" \
        --arg product_line "WorkPlus SE" \
        --arg admin_url "${admin_url}" \
        --arg admin_account "seadmin" \
        --arg admin_password "seadmin" \
        --arg service_schema "${service_schema}" \
        --arg service_public_host "${service_public_host}" \
        --arg error_message "${result_message}" \
        --arg raw "${raw_log}" \
        --arg diagnosis "${diagnosis_log}" \
        '{deploy_record_id:$deploy_record_id,record_status:$record_status,provider:$provider,product_line:$product_line,admin_url:$admin_url,admin_account:$admin_account,admin_password:$admin_password,service_schema:$service_schema,service_public_host:$service_public_host,error_message:$error_message,raw:({version:"se",message:$raw,diagnosis:$diagnosis}|tostring)}')
    local response
    response=$(curl --silent --show-error --connect-timeout 10 --request POST \
        --url "${IDC_CALLBACK_URL}" \
        --header 'Content-Type: application/json' \
        --header "Authorization: Bearer ${IDC_CALLBACK_TOKEN}" \
        --data "${payload}" 2>&1)
    local exit_code=$?
    CALLBACK_SENT="true"
    {
        echo "[$(date +%Y%m%d-%H:%M:%S)] se callback request"
        echo "url: ${IDC_CALLBACK_URL}"
        echo "payload: ${payload}"
        echo "exit_code: ${exit_code}"
        echo "response: ${response}"
        echo ""
    } >>"${platform_callback_log}" 2>&1
}

sync_failed_on_exit() {
    local exit_code=$?
    if [[ ${exit_code} -ne 0 && "${CALLBACK_ENABLED}" == "true" ]]; then
        local install_log="$(read_file_safe "${platform_msg_log}")"
        local error_log="$(read_file_safe "${platform_err_log}")"
        local process_log="$(read_file_safe "${platform_pro_log}")"
        local initialize_log="$(read_file_safe "${HOME}/.initialize")"
        local diagnosis_log="$(grep -E 'access failed|connection refused|失败|failed|Error|错误' "${platform_err_log}" 2>/dev/null)"
        sync_deploy_result "failed" "WorkPlus-SE部署失败" "${install_log}--${process_log}--${error_log}--${initialize_log}" "${diagnosis_log}"
    fi
}

trap sync_failed_on_exit EXIT

to_lowercase () {
    echo "$1" | sed "y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/"
}

to_uppercase () {
    echo "$1" | sed "y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/"
}

root_checking () {
    if [[ ! $( id -u ) -eq 0 ]]; then
        echo "您必须登录到root用户环境才能执行本脚本, 请登录成功后重试"|tee -a ${platform_err_log}
        echo "To perform this action you must be logged in with root rights, program exit."|tee -a ${platform_err_log}
        exit 1;
    fi
}

get_os () {
    OS=`to_lowercase \`uname\``

    if [[ "${OS}" == "windowsnt" ]]; then
        echo "Not supported OS, program exit.";
        exit 1;
    elif [[ "${OS}" == "darwin" ]]; then
        echo "Not supported OS, program exit.";
        exit 1;
    else
        OS=`uname`

        if [[ "${OS}" == "SunOS" ]] ; then
            echo "Not supported OS, program exit.";
            exit 1;
        elif [[ "${OS}" == "AIX" ]] ; then
            echo "Not supported OS, program exit.";
            exit 1;
        elif [[ "${OS}" == "Linux" ]] ; then
            MACH=`uname -m`
            KERNEL=`uname -r`

            if [[ -f /etc/opencloudos-release ]] ; then
                DIST=`cat /etc/opencloudos-release |sed s/\ release.*//`
                REV=`cat /etc/opencloudos-release | sed s/.*release\ // | sed s/\ .*//`

            elif [[ -f /etc/tencentos-release ]] ; then
                DIST=`cat /etc/tencentos-release |sed s/\ release.*//`
                REV=`cat /etc/tencentos-release | sed s/.*release\ // | sed s/\ .*//`

            elif [[ -f /etc/openEuler-release ]] ; then
                DIST=`cat /etc/openEuler-release |sed s/\ release.*//`
                REV=`cat /etc/openEuler-release | sed s/.*release\ // | sed s/\ .*//`

            elif [[ -f /etc/hce-release ]] ; then
                DIST=`cat /etc/hce-release |sed s/\ release.*//`
                REV=`cat /etc/hce-release | sed s/.*release\ // | sed s/\ .*//`

            elif [[ -f /etc/euleros-release ]] ; then
                DIST=`cat /etc/euleros-release |sed s/\ release.*//`
                REV=`cat /etc/euleros-release | sed s/.*release\ // | sed s/\ .*//`

            elif [[ -f /etc/fedora-release ]] ; then
                DIST=`cat /etc/fedora-release |sed s/\ release.*//`
                REV=`cat /etc/fedora-release | sed s/.*release\ // | sed s/\ .*//`

            elif [[ -f /etc/SuSE-release ]] ; then
                DIST='SuSe'
                REV=`cat /etc/os-release  | grep '^VERSION_ID' | awk -F=  '{ print $2 }' |  sed -e 's/^"//'  -e 's/"$//'`

            elif [[ -f /etc/redhat-release ]] ; then
                DIST=`cat /etc/redhat-release |sed s/\ release.*//`
                REV=`cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//`
                source /etc/os-release

            elif [[ -f /etc/debian_version ]] ; then
                DIST='Debian'
                REV=`cat /etc/debian_version`
                if [[ -f /etc/lsb-release ]] ; then
                    DIST=`cat /etc/lsb-release | grep '^DISTRIB_ID' | awk -F=  '{ print $2 }'`
                    REV=`cat /etc/lsb-release | grep '^DISTRIB_RELEASE' | awk -F=  '{ print $2 }'`
                elif [[ -f /etc/lsb_release ]]; then
                    DIST=`lsb_release -a 2>&1 | grep 'Distributor ID:' | awk -F ":" '{print $2 }'`
                    REV=`lsb_release -a 2>&1 | grep 'Release:' | awk -F ":" '{print $2 }'`
                fi

            elif [[ -f /etc/os-release ]] ; then
                DIST=`cat /etc/os-release | grep -sw 'ID' | awk -F=  '{ print $2 }' | sed -e 's/^"//' -e 's/"$//'`
                REV=`cat /etc/os-release | grep -sw 'VERSION_ID' | awk -F=  '{ print $2 }' | sed -e 's/^"//' -e 's/"$//'`
            fi
        fi
    fi
}

update_source () {
    get_os
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    ##已经部署有资源的环境跳过此步骤
    if command -v docker &>/dev/null && [[ $(docker images 2>/dev/null | grep -E "/workapps/|/workplus/" | wc -l) -gt 1 ]]; then
        return
    fi
    echo "checking the operating system - waiting for it ..."
    #部分操作系统需要更新安装源,否则无法使用在线部署方式;无法联网的环境则跳过;
    echo -e "\n检查服务器连接互联网的可用性, 请稍等..." >> ${platform_msg_log} 2>&1
    ping -c 2 -i 1 mirrors.aliyun.com >> ${platform_msg_log} 2>&1
    if [ $? -eq 0 ];then
       if [[ "${DIST}" == CentOS* ]]; then
          if [ "${VERSION_ID}" == "7" ];then
             /bin/mkdir -p /etc/yum.repos.d/backup-$(date +%Y%m%d%H) > /dev/null 2>&1
             /bin/mv -f /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup-$(date +%Y%m%d%H)/ > /dev/null 2>&1
             curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.aliyun.com/repo/Centos-7.repo > /dev/null 2>&1
             /bin/sed -i "/mirrors.cloud.aliyuncs.com/d" /etc/yum.repos.d/CentOS-Base.repo >> ${platform_msg_log} 2>&1
#            echo "update the installation source - waiting for it ..."
#            yum clean all >> ${platform_msg_log} 2>&1
#            yum makecache >> ${platform_msg_log} 2>&1
          fi
          if [ "${VERSION_ID}" == "8" ];then
             /bin/mkdir -p /etc/yum.repos.d/backup-$(date +%Y%m%d%H) > /dev/null 2>&1
             /bin/mv -f /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup-$(date +%Y%m%d%H)/ > /dev/null 2>&1
             curl -o /etc/yum.repos.d/Centos-vault-8.5.2111.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo > /dev/null 2>&1
             curl -o /etc/yum.repos.d/epel-archive-8.repo https://mirrors.aliyun.com/repo/epel-archive-8.repo > /dev/null 2>&1
             echo "update the installation source - waiting for it ..."|tee -a ${platform_msg_log}
             yum clean all >> ${platform_msg_log} 2>&1
             yum makecache >> ${platform_msg_log} 2>&1
          fi
       elif [[ "${DIST}" == "Ubuntu" ]]; then
          #[ ! -f /etc/apt/sources.list ] && curl -o /etc/apt/sources.list https://w6s-docker.oss-cn-shenzhen.aliyuncs.com/ubuntu22.04.repo > /dev/null 2>&1
          if [ "${REV}" == "24.04" ]; then
             /bin/mv -f /etc/apt/sources.list.d/ubuntu.sources  /etc/apt/sources.list.d/ubuntu.sources-$(date +%Y%m%d%H)
             curl -o /etc/apt/sources.list.d/ubuntu.sources https://w6s-docker.oss-cn-shenzhen.aliyuncs.com/ubuntu24.04.repo > /dev/null 2>&1
             echo "update the installation source - waiting for it ..."|tee -a ${platform_msg_log}
             systemctl stop unattended-upgrades apt-daily.timer apt-daily-upgrade.timer
             killall apt > /dev/null 2>&1
             #pkill -9 -f unattended-upgrade > /dev/null 2>&1
             dpkg --configure -a
             apt update >> ${platform_msg_log} 2>&1
          fi
       elif [[ "${DIST}" == "Red Hat Enterprise Linux Server" ]]; then
          if [[ -n $(echo "${VERSION_ID}" | grep '7.') ]];then
             curl -o /etc/yum.repos.d/CentOS-Base.repo http://mirrors.163.com/.help/CentOS7-Base-163.repo > /dev/null 2>&1
             sed -i 's/$basearch/x86_64/g' /etc/yum.repos.d/CentOS-Base.repo > /dev/null 2>&1
             sed -i 's/$releasever/7/g' /etc/yum.repos.d/CentOS-Base.repo > /dev/null 2>&1
             echo "update the installation source - waiting for it ..."|tee -a ${platform_msg_log}
             yum clean all >> ${platform_msg_log} 2>&1
             yum makecache >> ${platform_msg_log} 2>&1
          fi
       elif [[ "${DIST}" == "Red Hat Enterprise Linux" ]]; then
          if [[ -n $(echo "${VERSION_ID}" | grep '8.') ]];then
             /bin/mkdir -p /etc/yum.repos.d/backup-se > /dev/null 2>&1
             /bin/mv /etc/yum.repos.d/*.repo /etc/yum.repos.d/backup-se/ > /dev/null 2>&1
             curl -o /etc/yum.repos.d/Centos-vault-8.5.2111.repo https://mirrors.aliyun.com/repo/Centos-vault-8.5.2111.repo > /dev/null 2>&1
             curl -o /etc/yum.repos.d/epel-archive-8.repo https://mirrors.aliyun.com/repo/epel-archive-8.repo > /dev/null 2>&1
             echo "update the installation source - waiting for it ..."|tee -a ${platform_msg_log}
             yum clean all >> ${platform_msg_log} 2>&1
             yum makecache >> ${platform_msg_log} 2>&1
          fi
       fi
    else
       echo -e "\n服务器无法访问互联网, 跳过更新安装源" >> ${platform_msg_log} 2>&1
    fi
}

get_prefix () {
    if file_exists ${HOME}/.urlprefix; then
        url_prefix=$(cat ${HOME}/.urlprefix)
    else
        url_prefix=http
    fi
}

get_ip () {
    if [ -n "${HOST_INPUT}" ]; then
        WP_HOST="${HOST_INPUT}"
    elif file_exists ${HOME}/.hostinfo; then
        WP_HOST=$(cat ${HOME}/.hostinfo)
    elif command_exists ip ; then
        WP_HOST=`ip a | grep inet | grep -v inet6 | grep -v 127.0.0.1 |awk '{print $2}'|awk -F '/' '{print $1}'| head -n 1`;
    elif command_exists ifconfig ; then
        WP_HOST=`ifconfig -a | grep inet | grep -v inet6 | grep -v 127.0.0.1 |awk '{print $2}'|tr -d "addr:" | head -n 1`;
    fi

    if [[ -z "${WP_HOST}" ]]; then
       echo -e "\n无法获取有效地址作为平台的访问地址, 安装中断退出"|tee -a ${platform_err_log}
       echo "失败原因: 您执行脚本没有传入服务器参数, 或者服务器没有查看ip地址的系统命令" |tee -a ${platform_err_log}
       echo "请您使用 \"/bin/bash ./$(basename $0) 服务器IP\" 的方式重新执行安装"|tee -a ${platform_err_log}
       exit 1
    fi
}

get_lanip () {
    if [ -n "${LANIP}" ]; then
        LANIP="${LANIP}"
    elif file_exists ${HOME}/.lanip; then
        LANIP=$(cat ${HOME}/.lanip)
    elif command_exists ip ; then
        LANIP=`ip a | grep inet | grep -v inet6 | grep -v 127.0.0.1 |awk '{print $2}'|awk -F '/' '{print $1}'| head -n 1`;
    elif command_exists ifconfig ; then
        LANIP=`ifconfig -a | grep inet | grep -v inet6 | grep -v 127.0.0.1 |awk '{print $2}'|tr -d "addr:" | head -n 1`;
    fi
}

get_dir () {
    if file_exists ${HOME}/.dirinfo; then
        WP_DIR=$(cat ${HOME}/.dirinfo)
    fi
}

get_version () {
    if file_exists ${HOME}/.verinfo; then
        WP_VERSION=$(cat ${HOME}/.verinfo)
    fi
}

get_log_level () {
    if file_exists ${HOME}/.loginfo; then
        WP_LOG=$(cat ${HOME}/.loginfo)
    fi
}

get_im_ssl () {
    if file_exists ${HOME}/.imssl; then
        IM_SSL=$(cat ${HOME}/.imssl)
    fi
}

get_im_type () {
    if file_exists ${HOME}/.imtype; then
        IM_TYPE=$(cat ${HOME}/.imtype)
    fi
}

get_driver () {
    ##获取数据库驱动(mysql/shentong/dm8)
    if file_exists ${HOME}/.dbdriver; then
        DB_DRIVER=$(cat ${HOME}/.dbdriver)
    else
        DB_DRIVER=${CORE_DATABASE_DRIVER}
    fi
    echo ${DB_DRIVER} > ${HOME}/.dbdriver

    ##获取是否自动建表开关(on/off)
    if file_exists ${HOME}/.dbsetup; then
        DB_SETUP=$(cat ${HOME}/.dbsetup)
    else
        DB_SETUP=off
    fi
    echo ${DB_SETUP} > ${HOME}/.dbsetup
}

check_os () {
    get_os
    if [[ -z ${KERNEL} || -z ${DIST} || -z ${REV} ]]; then
        echo "$KERNEL, $DIST, $REV";
        echo "Not supported OS, program exit."|tee -a ${platform_err_log}
        echo "您当前的操作系统不被支持, 安装中断退出."|tee -a ${platform_err_log}
        echo "请使用官网部署入口建议列表的操作系统版本."|tee -a ${platform_err_log}
        exit 1;
    fi

    ##银河麒麟/统信UOS等系统不允许用桌面版部署
    if [ -f "/etc/os-release" ]; then
        if grep -qiE "Desktop|桌面操作系统" /etc/os-release; then
            echo "======================================================================"
            echo "错误：不支持在桌面版操作系统上部署后端服务, 请更换服务器版操作系统部署!"|tee -a ${platform_err_log}
            echo "Error: Installation is not supported on desktop operating systems!"|tee -a ${platform_err_log}
            echo "======================================================================"
            exit 1
        fi
    fi
}

check_kernel () {
    MIN_NUM_ARR=(3 10 0);
    CUR_NUM_ARR=();

    CUR_STR_ARR=$(echo ${KERNEL} | grep -Po "[0-9]+\.[0-9]+\.[0-9]+" | tr "." " "|head -n 1);
    for CUR_STR_ITEM in ${CUR_STR_ARR}
    do
        CUR_NUM_ARR=(${CUR_NUM_ARR[@]} ${CUR_STR_ITEM})
    done

    INDEX=0;

    while [[ $INDEX -lt 3 ]]; do
        if [[ ${CUR_NUM_ARR[INDEX]} -lt ${MIN_NUM_ARR[INDEX]} ]]; then
            echo "Not supported OS Kernel, program exit."|tee -a ${platform_err_log}
            exit 1;
        elif [[ ${CUR_NUM_ARR[INDEX]} -gt ${MIN_NUM_ARR[INDEX]} ]]; then
            INDEX=3
        fi
        (( INDEX++ ))
    done
}

check_cpu_cores() {
    cpu_cores=$(grep -c '^processor' /proc/cpuinfo)
    if [ "${cpu_cores}" -lt "${CORE_REQUIREMENTS}" ]; then
        error_messages+=("CPU核数不满足要求: 当前${cpu_cores}核, 要求至少${CORE_REQUIREMENTS}核;")
    fi
}

check_physical_memory() {
    TOTAL_MEMORY=$(free -m | grep -oP '\d+' | head -n 1);
    TOTAL_MEMORY_GB=$(awk "BEGIN {printf \"%.1f\", ${TOTAL_MEMORY}/1024}")
    if [ ${TOTAL_MEMORY} -lt ${MEMORY_REQUIREMENTS} ]; then
        error_messages+=("物理内存大小不符合要求: 当前为${TOTAL_MEMORY_GB}G, 要求至少16G;")
    fi
}

check_disk_space() {
    AVAILABLE_DISK_SPACE=$(df -BG /  | tail -1 | awk '{ print $4 }' | sed 's/G//');
    if [[ ${AVAILABLE_DISK_SPACE} -lt ${DISK_REQUIREMENTS} ]]; then
        error_messages+=("系统分区(/)剩余空间不符合要求: 当前可用${AVAILABLE_DISK_SPACE}G, 要求至少${DISK_REQUIREMENTS}G可用空间;")
    fi

    AVAILABLE_DISK_SPACE_VAR=$(df -BG /var  | tail -1 | awk '{ print $4 }' | sed 's/G//');
    if [[ ${AVAILABLE_DISK_SPACE_VAR} -lt ${DISK_REQUIREMENTS} ]]; then
        error_messages+=("系统分区(/var)剩余空间不符合要求: 当前可用${AVAILABLE_DISK_SPACE_VAR}G, 要求至少${DISK_REQUIREMENTS}G可用空间;")
    fi

    AVAILABLE_DISK_SPACE_HOME=$(df -BG /home  | tail -1 | awk '{ print $4 }' | sed 's/G//');
    if [[ ${AVAILABLE_DISK_SPACE_HOME} -lt ${DISK_REQUIREMENTS} ]]; then
        error_messages+=("用户分区(/home)剩余空间不符合要求: 当前可用${AVAILABLE_DISK_SPACE_HOME}G, 要求至少${DISK_REQUIREMENTS}G可用空间;")
    fi
}

check_selinux() {
    if command_exists sestatus; then
        selinux_status=$(getenforce 2>/dev/null)
        #获取selinux配置文件中的永久状态
        selinux_config=$(grep -E '^SELINUX=' /etc/selinux/config | awk -F= '{print $2}' | tr -d ' ')

        ##处理状态获取失败的情况
        if [ -z "$selinux_status" ]; then
            selinux_status="未知"
        fi
        if [ -z "$selinux_config" ]; then
            selinux_config="未配置"
        fi

        ##判断是否非disable状态(运行时或配置文件任一非disable则提示)
        if [ "$selinux_status" != "Disabled" ] || [ "$selinux_config" != "disabled" ]; then
            error_messages+=("SELinux策略不符合要求: 当前运行状态为$selinux_status, 配置文件状态为$selinux_config;
            请按照以下步骤禁用SELinux策略并重启生效：
            步骤1. 执行命令: sed -i 's/SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config;  ##设置禁用.
            步骤2. 执行命令: reboot;   ##重启服务器使步骤1的设置生效.")
        fi
    fi
}

check_hardware () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi

    ##如果已经部署了环境且部分进程已在运行中,再次执行就不再检查硬件环境
    if command -v docker &>/dev/null && [[ $(docker ps|grep -E '/workplus|/workapps|/workdbs|/meet/'|wc -l) -gt 10 ]]; then
       return
    fi

    error_messages=()
    check_cpu_cores
    check_physical_memory
    check_disk_space
    check_selinux
    if [ ${#error_messages[@]} -eq 0 ]; then
        echo "✅ 所有检测项均符合要求" >> ${platform_msg_log} 2>&1
    else
        echo -e "\033[1;33m❌ The following issues do not meet the installation requirements!\033[0m"
        echo -e "\033[1;33m❌ 检测到服务器存在以下问题不符合部署要求, 请修正或更换服务器再部署!\033[0m"|tee -a ${platform_err_log}
        # 逐条输出异常信息，保持格式整洁
        for i in "${!error_messages[@]}"; do
            echo "$((i+1)). ${error_messages[$i]}"|tee -a ${platform_err_log}
        done
        exit 1;
    fi
}

check_url_prefix () {
#    get_prefix
#    echo "[This is Important!!!] 请选择访问WorkPlus平台的网络协议, http or https?"
#    read -ep "[This is Important!!!] Please choose the protocol for visit WorkPlus, http or https? [current is: ${url_prefix}]: " input_prefix
#    if [[ -n "${input_prefix}" ]];then
#        if [[ "${input_prefix}" == "https" ]] || [[ "${input_prefix}" == "http" ]];then
#            url_prefix=${input_prefix}
#        else
#            echo -e "\033[1;31mPlease input http or https\033[0m"
#            exit 1
#        fi
#    else
#        url_prefix=${url_prefix}
#    fi
#    if [[ "${url_prefix}" == "https" ]];then
#        echo -e "\033[1;33m您已选择https协议, 请确认您有可用的域名和有效ssl证书, 如未具备请退出重新选择http协议\033[0m"
#        echo -e "\033[1;33mYou have choose https, So you must have a domain and a valid ssl certificate, If not, Please exit and choose http\033[0m"
#        read -ep "Continue [Y/N]? " choice
#        case "$choice" in
#            y|Y )
#            echo -e "\033[1;33m\033[05m您已选择https协议, 在下一步您必须输入域名作为WorkPlus平台的访问地址\033[0m";
#            sleep 1
#            ;;
#            n|N )
#            exit 0
#            ;;
#            * )
#            echo "Please enter y or n"|tee -a ${platform_err_log}
#            exit 0
#            ;;
#        esac
#    fi

    url_prefix=$1
    if [[ "${url_prefix}" != "http" && "${url_prefix}" != "https" ]]; then
        url_prefix=http
    fi
    echo "${url_prefix}" > "${HOME}/.urlprefix"
}

check_ip () {
     get_ip
#    echo "[This is Important!!!] 请输入访问WorkPlus平台的IP地址或域名地址"
#    read -ep "[This is Important!!!] Please input ip or domain for visit WorkPlus [current is: ${WP_HOST}]: " external_host
#    if [[ "${external_host}" == "127.0.0.1" ]] || [[ "${external_host}" == "localhost" ]] || [[ "${external_host}" == "10.0.0.1" ]];then
#        echo "Failed, Please enter a valid ip address or domain address"
#        check_ip
#    fi
#    if [[ -n ${external_host} ]]; then
#        read -ep "[This is Important!!!] Enter same external ip or domain again: " confirmed_host
#        if [[ "$external_host" == "$confirmed_host" ]]; then
#            WP_HOST=${confirmed_host};
#          else
#            check_ip
#        fi
#    fi
    ##判断是否是IPv4
    if [[ "$WP_HOST" =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; then
        echo "Detected IPv4: $WP_HOST" >> ${platform_msg_log} 2>&1
#        if [[ "${url_prefix}" == "https" ]];then
#            echo -e "\033[1;31mYou have choose https, So you must input a domain as the visit address\033[0m"|tee -a ${platform_err_log}
#            exit 1
#        fi
    ##判断是否是域名格式(不含协议、端口、路径)
    elif [[ "$WP_HOST" =~ ^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,}$ ]] && ! [[ "$WP_HOST" =~ [:/] ]]; then
         echo "Detected Domain: $WP_HOST" >> ${platform_msg_log} 2>&1
    else
         echo "The host address you entered: ${WP_HOST}"
         echo "Error: Invalid format. Must be IPv4 (e.g., 192.168.1.1) or Domain (e.g., example.com)."|tee -a ${platform_err_log}
         echo "错误: 访问地址格式异常, 请使用标准的IPv4地址或标准的域名地址部署."|tee -a ${platform_err_log}
         exit 1
    fi
    echo ${WP_HOST} > ${HOME}/.hostinfo

    ##判断内网IP格式是否正常
    if [[ "${LANIP}" == "127.0.0.1" ]] || [[ "${external_host}" == "localhost" ]] || [[ "${external_host}" == "10.0.0.1" ]];then
        echo "The lanip address: ${LANIP}"
        echo "Failed, the lanip not allow to use '127.0.0.1/localhost/10.0.0.1' "|tee -a ${platform_err_log}
        exit 1
    fi

    if [[ ! "${LANIP}" =~ ^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$ ]]; then
        echo "The lanip address: ${LANIP}"
        echo "Failed, Please enter a valid ip address for lanip"|tee -a ${platform_err_log}
        exit 1
    fi

    echo ${LANIP} > ${HOME}/.lanip
}

check_dir () {
    get_dir
    if [[ -n ${WP_DIR} ]]; then
        WP_DIR=${WP_DIR}
        echo ${WP_DIR} > ${HOME}/.dirinfo
    fi
}

check_version () {
    get_version
    if [[ -n ${WP_VERSION} ]];then
        WP_VERSION=${WP_VERSION}
        echo ${WP_VERSION} > ${HOME}/.verinfo
    fi
}

check_log_level () {
    get_log_level
    if [[ -n ${WP_LOG} ]];then
        WP_LOG=${WP_LOG}
        echo ${WP_LOG} > ${HOME}/.loginfo
    fi
}

define_ports () {
    if file_exists ${HOME}/.portlist; then
      source ${HOME}/.portlist;
    else
      echo -e "DASH_PORT=9910\nHTTP_PORT=9911\nHTML_PORT=9912\nDOCS_PORT=9921\nMEET_PORT=9920\nUDPS_PORT=10001\nMBIM_PORT=8020\nPCIM_PORT=8021" > ${HOME}/.portlist;
      source ${HOME}/.portlist;
    fi
}

check_ports () {
    proc_nginx=$(docker ps | grep "${NGINX_CONTAINER_NAME}"|wc -l)
    if [ ${proc_nginx} = 0 ];then
      timeout 5 bash -c "</dev/tcp/127.0.0.1/${MBIM_PORT}" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口${MBIM_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
      timeout 5 bash -c "</dev/tcp/127.0.0.1/${PCIM_PORT}" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口${PCIM_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
      timeout 5 bash -c "</dev/tcp/127.0.0.1/${DASH_PORT}" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口${DASH_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
      timeout 5 bash -c "</dev/tcp/127.0.0.1/${HTTP_PORT}" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口${HTTP_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
      timeout 5 bash -c "</dev/tcp/127.0.0.1/${HTML_PORT}" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口${HTML_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
      timeout 5 bash -c "</dev/tcp/127.0.0.1/${DOCS_PORT}" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口${DOCS_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
      timeout 5 bash -c "</dev/tcp/127.0.0.1/${MEET_PORT}" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口${MEET_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
      timeout 5 bash -c "</dev/tcp/127.0.0.1/9913" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口9913已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
      timeout 5 bash -c "</dev/tcp/127.0.0.1/9914" > /dev/null 2>&1
      [ $? -eq 0 ] && echo "端口9914已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
    fi

    proc_meetapi=$(docker ps | grep 'workapps/meet-backend'|wc -l)
    if [ ${proc_meetapi} = 0 ];then
	    timeout 5 bash -c "</dev/tcp/127.0.0.1/${MEETAPI_PORT}" > /dev/null 2>&1
	    [ $? -eq 0 ] && echo "端口${MEETAPI_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
    fi

    ##collabora 端口检测, 若本产品 collabora 容器已在运行则视为自身占用, 不阻断重装
    proc_collabora=$(docker ps | grep "${APP_COLLABORA_CONTAINER_NAME}"|wc -l)
    if [ ${proc_collabora} = 0 ];then
	    timeout 5 bash -c "</dev/tcp/127.0.0.1/${COLLABORA_HOST_PORT}" > /dev/null 2>&1
	    [ $? -eq 0 ] && echo "端口${COLLABORA_HOST_PORT}已被其它进程占用,请释放该端口再重新安装"|tee -a ${platform_err_log} && exit 1
    fi
}

check_prompt() {
    check_url_prefix ${URL_PREFIX}
    check_ip
    check_dir
    check_version
    check_log_level
#    echo ""
#    echo "Install WorkPlus: [visit_addr=${WP_HOST}, visit_protocol=${url_prefix}, version=${WP_VERSION}, directory=${WP_DIR}]"
#    read -ep "Continue [Y/N/C]? " choice
#    case "$choice" in
#        y|Y )
#        echo -e "\033[1;33mInstalling WorkPlus, This may take a few minutes ...\033[0m"|tee -a ${platform_msg_log};
#        echo "";
#        ;;
#        n|N )
#        check_prompt
#        ;;
#        c|C )
#        exit 0;
#        ;;
#        * )
#        echo "Please, enter Y, N or C to cancel.";
#        check_prompt
#        ;;
#    esac
}

#check_lanip () {
#    if file_exists ${HOME}/.lanip; then
#       LANIP=$(cat ${HOME}/.lanip)
#    fi
#
#    if [ -z "${LANIP}" ];then
#       echo "无法获取本机有效内网IP地址,请在下一步手动输入"|tee -a ${platform_err_log}
#       read -ep "Unable to obtain a valid lan ip address, Please manually input: " lanipaddr
#       if [[ "${lanipaddr}" == "127.0.0.1" ]] || [[ "${lanipaddr}" == "localhost" ]] || [[ "${lanipaddr}" == "10.0.0.1" ]] || [[ "${lanipaddr}" == "" ]];then
#          echo -e "\n\033[1;31mPlease do not enter the ip address of the loop or null\033[0m\n"
#          check_lanip
#       else
#          LANIP=${lanipaddr}
#       fi
#    fi
#
#    echo ${LANIP} > ${HOME}/.lanip
#}

check_im_ssl () {
    get_im_ssl
    if [[ -z ${IM_SSL} ]]; then
        IM_SSL=off
        echo ${IM_SSL} > ${HOME}/.imssl
    fi
}

check_im_type () {
    get_im_type
    if [[ -z ${IM_TYPE} ]]; then
        IM_TYPE=netty
        echo ${IM_TYPE} > ${HOME}/.imtype
    fi
}

check_ipv4 () {
    ADDR="${WP_HOST}"
    PROTOCOL="${url_prefix}"
    IPV4_REGEX="^((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$"
    if [[ "$PROTOCOL" == "https" && "$ADDR" =~ $IPV4_REGEX ]]; then
        echo "======================================================================"
        echo "错误：当前平台访问协议设置为https，第1个地址参数不能是纯IPv4地址！"
        echo "原因：浏览器/操作系统 不信任 https://IPv4地址 的url格式访问！"
        echo "修正：如需https协议, 第1个地址参数请配置正确的二级域名格式地址！"
        echo "======================================================================"
        echo ""
        exit 1
    fi
}

check_mysql () {
    echo -e "\n检查服务器宿主机是否已存在MySQL相关进程" >> ${platform_msg_log} 2>&1
    mysql_process_count=$(ps -ef | grep -E "[m]ysqld_safe|[m]ysqld" | wc -l)

    if [ $mysql_process_count -gt 0 ]; then
       echo "服务器存在MySQL相关进程, 开始判断是宿主机还是容器进程" >> ${platform_msg_log} 2>&1

       found_host_process=false
       #使用文件描述符避免子shell问题
       while read line; do
       pid=$(echo $line | awk '{print $2}')
       echo "进程信息: $line" >> ${platform_msg_log} 2>&1

       if grep -q "docker" /proc/$pid/cgroup 2>/dev/null; then
           echo "进程${pid}是一个Docker容器内的进程" >> ${platform_msg_log} 2>&1
       else
           echo "发现服务器宿主机存在MySQL进程在运行" | tee -a ${platform_err_log}
           echo "请使用未安装任何软件的服务器进行部署" | tee -a ${platform_err_log}
           found_host_process=true
           break
       fi
       done < <(ps -ef | grep -E "[m]ysqld_safe|[m]ysqld"|grep -v '<defunct>')

       if [ "$found_host_process" = "true" ]; then
          exit 1
       fi
    else
       echo "服务器宿主机未发现MySQL相关进程" >> ${platform_msg_log} 2>&1
    fi
}

check_mongo () {
    echo -e "\n检查服务器宿主机是否已存在Mongo相关进程" >> ${platform_msg_log} 2>&1
    mongo_process_count=$(ps -ef | grep -w -E "[m]ongod" | wc -l)
    if [ $mongo_process_count -gt 0 ]; then
       echo "服务器存在Mongo相关进程, 开始判断是宿主机还是容器进程" >> ${platform_msg_log} 2>&1

       found_host_process=false
       #使用文件描述符避免子shell问题
       while read line; do
       pid=$(echo $line | awk '{print $2}')
       echo "进程信息: $line" >> ${platform_msg_log} 2>&1

       if grep -q "docker" /proc/$pid/cgroup 2>/dev/null; then
           echo "进程${pid}是一个Docker容器内的进程" >> ${platform_msg_log} 2>&1
       else
           echo "发现服务器宿主机存在Mongo进程在运行" | tee -a ${platform_err_log}
           echo "请使用未安装任何软件的服务器进行部署" | tee -a ${platform_err_log}
           found_host_process=true
           break
       fi
       done < <(ps -ef | grep -E "[m]ongod")

       if [ "$found_host_process" = "true" ]; then
          exit 1
       fi
    else
       echo "服务器宿主机未发现Mongo相关进程" >> ${platform_msg_log} 2>&1
    fi
}

check_redis () {
    echo -e "\n检查服务器宿主机是否已存在Redis相关进程" >> ${platform_msg_log} 2>&1
    redis_process_count=$(ps -ef | grep -w -E "[r]edis-server" | wc -l)
    if [ $redis_process_count -gt 0 ]; then
       echo "服务器存在Redis相关进程, 开始判断是宿主机还是容器进程" >> ${platform_msg_log} 2>&1

       found_host_process=false
       #使用文件描述符避免子shell问题
       while read line; do
       pid=$(echo $line | awk '{print $2}')
       echo "进程信息: $line" >> ${platform_msg_log} 2>&1

       if grep -q "docker" /proc/$pid/cgroup 2>/dev/null; then
           echo "进程${pid}是一个Docker容器内的进程" >> ${platform_msg_log} 2>&1
       else
           echo "发现服务器宿主机存在Redis进程在运行" | tee -a ${platform_err_log}
           echo "请使用未安装任何软件的服务器进行部署" | tee -a ${platform_err_log}
           found_host_process=true
           break
       fi
       done < <(ps -ef | grep -E "[r]edis-server")

       if [ "$found_host_process" = "true" ]; then
          exit 1
       fi
    else
       echo "服务器宿主机未发现Redis相关进程" >> ${platform_msg_log} 2>&1
    fi
}

check_minio () {
    echo -e "\n检查服务器宿主机是否已存在Minio相关进程" >> ${platform_msg_log} 2>&1
    minio_process_count=$(ps -ef | grep -w -E "[m]inio server" | wc -l)
    if [ $minio_process_count -gt 0 ]; then
       echo "服务器存在Minio相关进程, 开始判断是宿主机还是容器进程" >> ${platform_msg_log} 2>&1

       found_host_process=false
       #使用文件描述符避免子shell问题
       while read line; do
       pid=$(echo $line | awk '{print $2}')
       echo "进程信息: $line" >> ${platform_msg_log} 2>&1

       if grep -q "docker" /proc/$pid/cgroup 2>/dev/null; then
           echo "进程${pid}是一个Docker容器内的进程" >> ${platform_msg_log} 2>&1
       else
           echo "发现服务器宿主机存在Minio进程在运行" | tee -a ${platform_err_log}
           echo "请使用未安装任何软件的服务器进行部署" | tee -a ${platform_err_log}
           found_host_process=true
           break
       fi
       done < <(ps -ef | grep -E "[m]inio server")

       if [ "$found_host_process" = "true" ]; then
          exit 1
       fi
    else
       echo "服务器宿主机未发现Minio相关进程" >> ${platform_msg_log} 2>&1
    fi
}

get_process_logs () {
    echo "$(date +%Y%m%d-%H:%M:%S)记录后台进程运行日志" > ${platform_pro_log} 2>&1
    echo -e "\n$(date +%Y%m%d-%H:%M:%S)记录wp-server最新100行日志" >> ${platform_pro_log} 2>&1
    docker logs -n 50 wp-server >> ${platform_pro_log} 2>&1
    echo -e "\n$(date +%Y%m%d-%H:%M:%S)记录wp-http最新100行日志" >> ${platform_pro_log} 2>&1
    docker logs -n 30 wp-http >> ${platform_pro_log} 2>&1
    echo -e "\n$(date +%Y%m%d-%H:%M:%S)记录wp-dash最新100行日志" >> ${platform_pro_log} 2>&1
    docker logs -n 30 wp-dash >> ${platform_pro_log} 2>&1
}

initialize_report () {
    CORP_NAME='NULL'
    CONTACT_NAME='NULL'
    CONTACT_EMAIL='NULL'
    DOMAIN_URL="${URL_PREFIX}://${HOST_INPUT}:9910"
    REPORT_LOG="该通知仅说明客户开始执行了脚本，不代表最终部署结果。部署过程如果客户手动中断，或服务器异常断开导致的部署中断（非脚本自动熔断），不会再有任何失败或成功的通知推送。"

    INNER_CONTENT='[[{\"text\":\"自建服务器离线部署通知(可联网)\",\"tag\":\"text\"}],[{\"text\":\"\",\"tag\":\"text\"}],[{\"text\":\"产品分支：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"BeeWorks\",\"tag\":\"text\"}],[{\"text\":\"客户名字：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"'"${CONTACT_NAME}"'\",\"tag\":\"text\"}],[{\"text\":\"公司名称：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"'"${CORP_NAME}"'\",\"tag\":\"text\"}],[{\"text\":\"电子邮箱：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"'"${CONTACT_EMAIL}"'\",\"tag\":\"text\"}],[{\"text\":\"访问地址：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"'"${DOMAIN_URL}"'\",\"tag\":\"text\"}],[{\"text\":\"域ID标识：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"NULL\",\"tag\":\"text\"}],[{\"text\":\"部署通知：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"离线部署脚本触发执行\",\"style\":{\"color\":\"blue\"},\"tag\":\"text\"}],[{\"text\":\"\",\"tag\":\"text\"}],[{\"text\":\"通知说明：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"}],[{\"text\":\"'"${REPORT_LOG}"'\",\"tag\":\"text\"}]]'

    CONTENT_STRING='{\"content\":'"${INNER_CONTENT}"'}'

    data='{
          "body": {
          "content": "'"${CONTENT_STRING}"'"
          },
          "type": "rich_text"
    }'

    #echo "构建的JSON数据："
    #echo "$data"
    curl --no-progress-meter --request POST --connect-timeout 10 \
         --url https://api.beeworks.cn/v1/bots/webhooks/a7f826OGFjYWE3MzEwN2IxZGJhNmQyYzY4YjY1YTgyMDEd29ya3BsdXM6MDE5 \
         --header 'Content-Type: application/json' \
         --data "$data" >> ${platform_msg_log} 2>&1
}

initialize_check () {
    CORP_NAME='NULL'
    CONTACT_NAME='NULL'
    CONTACT_EMAIL='NULL'
    DOMAIN_URL="${URL_PREFIX}://${HOST_INPUT}:9910"
    DIAGNOSIS_MSG=$(grep -E 'access failed|connection refused' "${platform_err_log}")
    if [ -n "${DIAGNOSIS_MSG}" ];then
       if ! command_exists jq; then
          DIAGNOSIS_LOG="unknown"
       else
          DIAGNOSIS_LOG="$(grep -A 50 'Http interface failure log' ${platform_err_log})"
       fi
    else
       DIAGNOSIS_LOG="success"
    fi

    if ! command_exists jq; then
       INNER_CONTENT='[[{\"text\":\"自建服务器离线部署通知(可联网)\",\"tag\":\"text\"}],[{\"text\":\"\",\"tag\":\"text\"}],[{\"text\":\"产品分支：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"BeeWorks\",\"tag\":\"text\"}],[{\"text\":\"客户名字：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"'"${CONTACT_NAME}"'\",\"tag\":\"text\"}],[{\"text\":\"公司名称：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"'"${CORP_NAME}"'\",\"tag\":\"text\"}],[{\"text\":\"电子邮箱：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"'"${CONTACT_EMAIL}"'\",\"tag\":\"text\"}],[{\"text\":\"访问地址：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"'"${DOMAIN_URL}"'\",\"tag\":\"text\"}],[{\"text\":\"域ID标识：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"NULL\",\"tag\":\"text\"}],[{\"text\":\"部署通知：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"},{\"text\":\"离线部署脚本执行结束\",\"style\":{\"color\":\"blue\"},\"tag\":\"text\"}],[{\"text\":\"\",\"tag\":\"text\"}],[{\"text\":\"接口诊断：\",\"style\":{\"color\":\"grey\"},\"tag\":\"text\"}],[{\"text\":\"'"${DIAGNOSIS_LOG}"'\",\"tag\":\"text\"}]]'

        CONTENT_STRING='{\"content\":'"${INNER_CONTENT}"'}'

        data='{
             "body": {
             "content": "'"${CONTENT_STRING}"'"
             },
             "type": "rich_text"
        }'
    else
        data=$(jq -n \
        --arg contact_name "$CONTACT_NAME" \
        --arg corp_name "$CORP_NAME" \
        --arg contact_email "$CONTACT_EMAIL" \
        --arg domain_url "$DOMAIN_URL" \
        --arg domain_id "NULL" \
        --arg diagnosis "${DIAGNOSIS_LOG}" \
         '{
           "body": {
             "content": {
               "content": [
                 [{"text": "自建服务器离线部署通知(可联网)", "tag": "text"}],
                 [{"text": "", "tag": "text"}],
                 [
                   {"text": "产品分支：", "style": {"color": "grey"}, "tag": "text"},
                   {"text": "BeeWorks", "tag": "text"}
                 ],
                 [
                   {"text": "客户名字：", "style": {"color": "grey"}, "tag": "text"},
                   {"text": $contact_name, "tag": "text"}
                 ],
                 [
                   {"text": "公司名称：", "style": {"color": "grey"}, "tag": "text"},
                   {"text": $corp_name, "tag": "text"}
                 ],
                 [
                   {"text": "电子邮箱：", "style": {"color": "grey"}, "tag": "text"},
                   {"text": $contact_email, "tag": "text"}
                 ],
                 [
                   {"text": "访问地址：", "style": {"color": "grey"}, "tag": "text"},
                   {"text": $domain_url, "tag": "text"}
                 ],
                 [
                   {"text": "域ID标识：", "style": {"color": "grey"}, "tag": "text"},
                   {"text": $domain_id, "tag": "text"}
                 ],
                 [
                   {"text": "执行结果：", "style": {"color": "grey"}, "tag": "text"},
                   {"text": "IM完成", "style": {"color": "blue"}, "tag": "text"}
                 ],
                 [{"text": "", "tag": "text"}],
                 [
                   {"text": "接口诊断：", "style": {"color": "grey"}, "tag": "text"}
                 ],
                 [
                   {"text": $diagnosis, "tag": "text"}
                 ]
               ]
             }
           },
           "type": "rich_text"
         }' | jq -c '.body.content = (.body.content | tostring)')
    fi

    curl --no-progress-meter --request POST --connect-timeout 10 \
         --url https://api.beeworks.cn/v1/bots/webhooks/a7f826OGFjYWE3MzEwN2IxZGJhNmQyYzY4YjY1YTgyMDEd29ya3BsdXM6MDE5 \
         --header 'Content-Type: application/json' \
         --data "$data" >> ${platform_msg_log} 2>&1
}

command_exists () {
    type "$1" &> /dev/null;
}

file_exists () {
    if [[ -z "$1" ]]; then
        echo "file path is empty"|tee -a ${platform_err_log}
        exit 1;
    fi

    if [[ -f "$1" ]]; then
        return 0; #true
    else
        return 1; #false
    fi
}

prepare_nginx_config_path () {
    local config_path="$1"

    if [[ -f "${config_path}" ]]; then
        return 0
    fi

    # Docker 对不存在的 -v 文件源会自动创建同名目录，先清理该空目录，
    # 否则后续 cat 无法写入，容器也会因文件/目录类型不匹配而启动失败。
    if [[ -d "${config_path}" ]]; then
        if ! rmdir "${config_path}" 2>/dev/null; then
            echo "错误: Nginx 配置路径是目录且无法安全删除: ${config_path}" | tee -a ${platform_err_log}
            return 1
        fi
    fi

    if [[ -e "${config_path}" ]]; then
        echo "错误: Nginx 配置路径不是普通文件: ${config_path}" | tee -a ${platform_err_log}
        return 1
    fi

    return 0
}

init_network () {
    EXIST_NAME=$(docker network ls --format "{{.Name}}" | { grep -x "${platform_name}" || true; })
    EXIST_SUBNET=$(docker network inspect $(docker network ls -q) --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null | { grep -x "${platform_subnet}" || true; })

    if [[ -z ${EXIST_NAME} ]]; then
        if [[ -n ${EXIST_SUBNET} ]]; then
            echo -e "\n警告: 预设网段${platform_subnet}已被其他网络使用, 使用新的网段" | tee -a ${platform_err_log}
            #显示使用该网段的网络
            docker network ls --filter driver=bridge --format "table {{.ID}}\t{{.Name}}\t{{.Driver}}" | while read id name driver; do
                subnet=$(docker network inspect $id --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null || echo "")
                if [[ "$subnet" == "$platform_subnet" ]]; then
                    echo -e "\n冲突网络: ID=$id, Name=$name, Subnet=$subnet" | tee -a ${platform_err_log}
                fi
            done
            platform_subnet='10.200.203.0/24'
            echo "使用新的网段${platform_subnet}" >> ${platform_err_log} 2>&1
        fi
        echo -e "\ncreate docker network - waiting for it ..." | tee -a ${platform_msg_log}
        docker network create --driver bridge --subnet=${platform_subnet} ${platform_name} | tee -a ${platform_msg_log}
    else
        echo -e "\nDocker网络${platform_name}已存在, 无须重复创建" >> ${platform_msg_log} 2>&1
        #验证现有网络的配置是否正确
        CURRENT_SUBNET=$(docker network inspect ${platform_name} --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null || echo "")
        if [[ "$CURRENT_SUBNET" != "$platform_subnet" ]]; then
            echo -e "\n警告: 现有网络${platform_name}的网段为${CURRENT_SUBNET}, 与预期${platform_subnet}不符" >> ${platform_msg_log} 2>&1
            echo -e "\n提示: 网段地址与预配置的不符不会影响正常使用, 安装操作继续进行" >> ${platform_msg_log} 2>&1
        fi
    fi
}

init_directories () {
    if [ -d ${WP_DIR}/fdfs ];then
      EXT_OVERLAYFS_DRIVER=fastdfs     #已安装fdfs的环境继续使用fdfs
      mkdir -p "${WP_DIR}/fdfs" >> /dev/null;
      chmod -R 0777 ${WP_DIR}/fdfs >> /dev/null;
    elif [ -f ${HOME}/.driver ]; then
      #从ce版本迁移过来的继续用localfs
      #echo localfs > ${HOME}/.driver
      EXT_OVERLAYFS_DRIVER=$(cat ${HOME}/.driver)
    else
      EXT_OVERLAYFS_DRIVER=s3          #新安装的环境使用minio代替fdfs
      mkdir -p "${WP_DIR}/minio/workplus" >> /dev/null;
    fi
    mkdir -p "${WP_DIR}/mongo/initdb.d" >> /dev/null;
    mkdir -p "${WP_DIR}/mongo/data" >> /dev/null;
    mkdir -p "${WP_DIR}/mongo/backup" >> /dev/null;
    mkdir -p "${WP_DIR}/mysql/temp" >> /dev/null;
    mkdir -p "${WP_DIR}/mysql/initdb.d" >> /dev/null;
    chmod 777 "${WP_DIR}/mysql/initdb.d" >> /dev/null;
    mkdir -p "${WP_DIR}/mysql/data" >> /dev/null;
    mkdir -p "${WP_DIR}/mysql/backup" >> /dev/null;
    mkdir -p "${WP_DIR}/redis/data" >> /dev/null;
    mkdir -p "${WP_DIR}/bpm/logs" >> /dev/null;
    mkdir -p "${WP_DIR}/form/logs" >> /dev/null;
    mkdir -p "${WP_DIR}/kaoqin/logs" >> /dev/null;
    mkdir -p "${WP_DIR}/html" >> /dev/null;
    mkdir -p ${WP_DIR}/nginx/{certs,project,logs} >> /dev/null;
    mkdir -p ${WP_DIR}/office/{conf,data,logs,lib,db,fonts,fonts-ds} >> /dev/null;

    if ! file_exists ${HOME}/.reginfo; then
        echo $(cat /proc/sys/kernel/random/uuid) > ${HOME}/.reginfo
    fi
}

init_db_files () {
    check_code_sql=$(curl -i -k -m 15 -o /dev/null -s -w %{http_code}"\n" http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/workplus_jobs.sql)
    if [ "${check_code_sql}" == "000" ];then
       echo -e "\n离线环境,检查数据库表结构文件是否存在,如不存在则从安装目录下重新复制" >> ${platform_msg_log} 2>&1
       echo "正在处理数据库表结构资源, 请稍等..." >> ${platform_msg_log} 2>&1
       [ ! -f "${WP_DIR}/mysql/temp/workplus-${DB_VERSION}-SE.sql" ] && /bin/cp -rva "${OFFLINE_DIR}/dbfiles/workplus-${DB_VERSION}-SE.sql" ${WP_DIR}/mysql/temp/|tee -a ${platform_msg_log}
       [ ! -f "${WP_DIR}/mysql/temp/calendar-${DB_VERSION}-SE.sql" ] && /bin/cp -rva "${OFFLINE_DIR}/dbfiles/calendar-${DB_VERSION}-SE.sql" ${WP_DIR}/mysql/temp/|tee -a ${platform_msg_log}
       [ ! -f "${WP_DIR}/mysql/temp/auditlog-${DB_VERSION}-SE.sql" ] && /bin/cp -rva "${OFFLINE_DIR}/dbfiles/auditlog-${DB_VERSION}-SE.sql" ${WP_DIR}/mysql/temp/|tee -a ${platform_msg_log}
       [ ! -f "${WP_DIR}/mysql/temp/workplus_jobs.sql" ] && /bin/cp -rva "${OFFLINE_DIR}/dbfiles/workplus_jobs.sql" ${WP_DIR}/mysql/temp/|tee -a ${platform_msg_log}
       [ ! -f "${WP_DIR}/mysql/temp/workplus_bpm.sql" ] && /bin/cp -rva "${OFFLINE_DIR}/dbfiles/workplus_bpm_v${APP_BPM_DB_VERSION}.sql" ${WP_DIR}/mysql/temp/workplus_bpm.sql|tee -a ${platform_msg_log}
       [ ! -f "${WP_DIR}/mysql/temp/workplus_meet_init.sql" ] && /bin/cp -rva "${OFFLINE_DIR}/dbfiles/workplus_meet_init.sql" ${WP_DIR}/mysql/temp/|tee -a ${platform_msg_log}
       [ ! -f "${WP_DIR}/mongo/initdb.d/workplus-${DB_VERSION}-SE.js" ] && /bin/cp -rva "${OFFLINE_DIR}/dbfiles/workplus-${DB_VERSION}-SE.js" ${WP_DIR}/mongo/initdb.d/|tee -a ${platform_msg_log}
       echo "正在复制数据备份脚本文件, 请稍等..." >> ${platform_msg_log} 2>&1
       [ ! -f "${WP_DIR}/mysql/backup/mysqlBackup_docker.sh" ] && /bin/cp -rva "${OFFLINE_DIR}/tools/mysqlBackup_docker.sh" ${WP_DIR}/mysql/backup/|tee -a ${platform_msg_log}
       [ ! -f "${WP_DIR}/mongo/backup/mongoBackup_docker.sh" ] && /bin/cp -rva "${OFFLINE_DIR}/tools/mongoBackup_docker.sh" ${WP_DIR}/mongo/backup/|tee -a ${platform_msg_log}
    else
       echo -e "\n下载数据库初始化表结构开始" >> ${platform_err_log} 2>&1
       curl -o ${WP_DIR}/mysql/temp/workplus-${DB_VERSION}-SE.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/workplus-${DB_VERSION}-SE.sql >> ${platform_msg_log} 2>&1
       [ $? -eq 0 ] && echo -e "下载核心数据库表结构文件成功" >> ${platform_msg_log} || { echo "下载核心数据库表结构文件失败,请确保网络连通正常再重新安装"|tee -a ${platform_err_log} && exit 1; }
       curl -o ${WP_DIR}/mysql/temp/calendar-${DB_VERSION}-SE.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/calendar-${DB_VERSION}-SE.sql >> ${platform_msg_log} 2>&1
       [ $? -eq 0 ] && echo -e "下载日程数据库表结构文件成功" >> ${platform_msg_log} || { echo "下载日程数据库表结构文件失败,请确保网络连通正常再重新安装"|tee -a ${platform_err_log} && exit 1; }
       curl -o ${WP_DIR}/mysql/temp/auditlog-${DB_VERSION}-SE.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/auditlog-${DB_VERSION}-SE.sql >> ${platform_msg_log} 2>&1
       [ $? -eq 0 ] && echo -e "下载审计数据库表结构文件成功" >> ${platform_msg_log} || { echo "下载审计数据库表结构文件失败,请确保网络连通正常再重新安装"|tee -a ${platform_err_log} && exit 1; }
       curl -o ${WP_DIR}/mysql/temp/workplus_jobs.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/workplus_jobs.sql >> ${platform_msg_log} 2>&1
       [ $? -eq 0 ] && echo -e "下载jobs数据库表结构文件成功" >> ${platform_msg_log} || { echo "下载jobs数据库表结构文件失败,请确保网络连通正常再重新安装"|tee -a ${platform_err_log} && exit 1; }
       curl -o ${WP_DIR}/mysql/temp/workplus_bpm.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/workplus_bpm_v${APP_BPM_DB_VERSION}.sql >> ${platform_msg_log} 2>&1
       [ $? -eq 0 ] && echo -e "下载bpm数据库表结构文件成功" >> ${platform_msg_log} || { echo "下载bpm数据库表结构文件失败,请确保网络连通正常,可再次尝试安装"|tee -a ${platform_err_log} && exit 1; }
       curl -o ${WP_DIR}/mysql/temp/workplus_meet_init.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/workplus_meet_init.sql >> ${platform_msg_log} 2>&1
       [ $? -eq 0 ] && echo -e "下载meetapi数据库表结构文件成功" >> ${platform_msg_log} || { echo "下载meetapi数据库表结构文件失败,请确保网络连通正常再重新安装"|tee -a ${platform_err_log} && exit 1; }
       curl -o ${WP_DIR}/mongo/initdb.d/workplus-${DB_VERSION}-SE.js  http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/workplus-${DB_VERSION}-SE.js >> ${platform_msg_log} 2>&1
       [ $? -eq 0 ] && echo -e "下载mongo数据库表结构文件成功" >> ${platform_msg_log} || { echo "下载mongo数据库表结构文件失败,请确保网络连通正常再重新安装"|tee -a ${platform_err_log} && exit 1; }
       echo "下载数据库初始化表结构结束" >> ${platform_msg_log} 2>&1

       echo -e "\n下载数据库备份脚本开始" >> ${platform_msg_log} 2>&1
       curl -o ${WP_DIR}/mysql/backup/mysqlBackup_docker.sh https://w6s-docker.oss-cn-shenzhen.aliyuncs.com/mysqlBackup_docker.sh >> ${platform_msg_log} 2>&1
       curl -o ${WP_DIR}/mongo/backup/mongoBackup_docker.sh https://w6s-docker.oss-cn-shenzhen.aliyuncs.com/mongoBackup_docker.sh >> ${platform_msg_log} 2>&1
       chmod +x ${WP_DIR}/mysql/backup/mysqlBackup_docker.sh > /dev/null 2>&1
       chmod +x ${WP_DIR}/mongo/backup/mongoBackup_docker.sh > /dev/null 2>&1
       echo "下载数据库备份脚本结束" >> ${platform_msg_log} 2>&1
    fi
}

repair_nginx_variable_proxy_uri () {
    local default_conf="${WP_DIR}/nginx/default.conf"

    [[ -f "${default_conf}" ]] || return 0

    # proxy_pass 使用变量作为上游地址后，带固定 URI 的写法不会自动保留原始请求路径。
    # 只修复脚本曾生成的已知写法，保留用户添加的其他 Nginx 自定义配置。
    /bin/sed -i \
        -e 's@proxy_pass http://$up_wp_dash/;@proxy_pass http://$up_wp_dash$request_uri;@g' \
        -e 's@proxy_pass http://$up_wp_http/;@proxy_pass http://$up_wp_http$request_uri;@g' \
        -e 's@proxy_pass http://$up_app_html/;@proxy_pass http://$up_app_html$request_uri;@g' \
        -e 's@proxy_pass http://$up_app_document/welcome/;@proxy_pass http://$up_app_document$request_uri;@g' \
        -e 's@proxy_pass http://$up_app_document/example/;@proxy_pass http://$up_app_document$request_uri;@g' \
        -e 's@proxy_pass http://$up_app_document/web-apps/;@proxy_pass http://$up_app_document$request_uri;@g' \
        -e 's@proxy_pass http://$up_app_document/cache/;@proxy_pass http://$up_app_document$request_uri;@g' \
        -e 's@proxy_pass http://$up_meet/;@proxy_pass http://$up_meet$request_uri;@g' \
        "${default_conf}"
}

repair_nginx_collabora_location () {
    local default_conf="${WP_DIR}/nginx/default.conf"
    local tmp_conf="${WP_DIR}/nginx/default.conf.collabora.tmp"

    [[ -f "${default_conf}" ]] || return 0
    [[ -n "${DOCS_PORT}" ]] || return 0
    # 幂等: 已配置 collabora 转发则跳过
    grep -q "up_app_collabora" "${default_conf}" && return 0

    # 在 DOCS 端口 server 块内首个 location 前插入根路径转发(仅新装模板未覆盖到时才执行)
    awk -v port="${DOCS_PORT}" '
        BEGIN { in_docs = 0; done = 0 }
        {
            if ($0 ~ "^[ \t]*listen[ \t]+" port "(;| ssl;)") { in_docs = 1 }
            if (in_docs == 1 && done == 0 && $0 ~ "^[ \t]*location[ \t]") {
                print "        ##DOCS端口根路径转发到 collabora 在线文档服务"
                print "        location / {"
                print "              set $up_app_collabora \"app-collabora:9980\";"
                print "              proxy_pass http://$up_app_collabora$request_uri;"
                print "              proxy_http_version 1.1;"
                print "              proxy_set_header Upgrade $http_upgrade;"
                print "              proxy_set_header Connection $proxy_connection;"
                print "              proxy_set_header Host $host;"
                print "              proxy_set_header X-Real-IP $remote_addr;"
                print "              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;"
                print "              proxy_set_header X-Forwarded-Proto $scheme;"
                print "              proxy_set_header X-Forwarded-Uri $request_uri;"
                print "              proxy_set_header X-Forwarded-Ssl on;"
                print "        }"
                done = 1
                in_docs = 0
            }
            print
        }
    ' "${default_conf}" > "${tmp_conf}" 2>>"${platform_err_log}"

    if [[ -s "${tmp_conf}" ]] && grep -q "up_app_collabora" "${tmp_conf}"; then
        /bin/cp -a "${default_conf}" "${default_conf}.bak-$(date +%Y%m%d-%H%M%S)" > /dev/null 2>&1
        /bin/mv "${tmp_conf}" "${default_conf}" > /dev/null 2>&1
        echo "已为 DOCS 端口(${DOCS_PORT})补充 collabora 根路径转发配置" >> "${platform_msg_log}" 2>&1
    else
        /bin/rm -f "${tmp_conf}" > /dev/null 2>&1
    fi
}

init_nginx_conf () {
    repair_nginx_variable_proxy_uri
    repair_nginx_collabora_location

    if [[ "${url_prefix}" == "http" ]];then
if ! file_exists ${WP_DIR}/nginx/nginx.conf; then
prepare_nginx_config_path "${WP_DIR}/nginx/nginx.conf" || exit 1
cat > ${WP_DIR}/nginx/nginx.conf << "EOF"
user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log warn;
pid   /var/run/nginx.pid;

worker_rlimit_nofile 65535;
events {
    worker_connections  65535;
}

http {
    resolver 127.0.0.11 valid=10s ipv6=off;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for" '
        'upstream_response_time $upstream_response_time request_time $request_time ';

#   access_log  off;
    access_log  /var/log/nginx/access.log main;

    map $http_upgrade $connection_upgrade {
            default upgrade;
            '' close;
    }

    include       /etc/nginx/conf.d/*.conf;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    server_tokens off;
    charset UTF-8;

    limit_conn_zone  $binary_remote_addr  zone=one:10m;
    limit_conn_log_level notice;

    types_hash_max_size 2048;
    client_max_body_size 0;
    client_header_buffer_size 128k;
    client_body_buffer_size 1m;
    large_client_header_buffers 4 64k;

    proxy_headers_hash_max_size 1024;
    proxy_headers_hash_bucket_size 128;
    proxy_max_temp_file_size 5120m;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout   65;
    keepalive_requests  10000;
    send_timeout        10;

    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;

    gzip  on;
    gzip_min_length 1k;
    gzip_buffers 4 32k;
    gzip_http_version 1.1;
    gzip_comp_level 3;
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json;
    gzip_disable "MSIE[1-6]";
    gzip_vary on;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_connect_timeout 60;
    proxy_send_timeout 120;
    proxy_read_timeout 120;
    proxy_buffering on;

    proxy_buffer_size 32k;
    proxy_buffers 16 32k;
    proxy_busy_buffers_size 64k;
    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
}

stream {
        resolver 127.0.0.11 valid=10s ipv6=off;
        log_format proxy '$remote_addr [$time_local] '
        '$protocol $status $bytes_sent $bytes_received '
        '$session_time "$upstream_addr" '
        '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

#       access_log  off;
        access_log  /var/log/nginx/stream.log  proxy;
        open_log_file_cache off;

        upstream im-mb {
                server 127.0.0.1:1;
        }
        upstream im-pc {
                server 127.0.0.1:1;
        }

        server {
                listen MBIM_PORT;
                set $up_im_mb "wp-server:8120";
                proxy_pass $up_im_mb;
        }
        server {
                listen PCIM_PORT;
                set $up_im_pc "wp-server:8121";
                proxy_pass $up_im_pc;
        }
}
EOF
/bin/sed -i "s@MBIM_PORT@${MBIM_PORT}@g" ${WP_DIR}/nginx/nginx.conf > /dev/null 2>&1
/bin/sed -i "s@PCIM_PORT@${PCIM_PORT}@g" ${WP_DIR}/nginx/nginx.conf > /dev/null 2>&1
fi

if ! file_exists ${WP_DIR}/nginx/default.conf; then
prepare_nginx_config_path "${WP_DIR}/nginx/default.conf" || exit 1
cat > ${WP_DIR}/nginx/default.conf << "EOF"
server {
        listen DASH_PORT;
        listen 9914;
        server_name _;

        location / {
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for:$remote_port;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
              set $up_wp_dash "wp-dash:9000";
              proxy_pass http://$up_wp_dash$request_uri;
        }
}
server {
        listen HTTP_PORT;
        listen 9913;
        server_name _;

        location /v1/sse/ {
              set $up_wp_http "wp-http:9000";
              proxy_pass http://$up_wp_http$request_uri;
              proxy_set_header Host $host:$server_port;
              proxy_cache off;
              proxy_buffering off;
              proxy_connect_timeout 60s;
              proxy_send_timeout 60s;
              proxy_read_timeout 60s;
        }
        location / {
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for:$remote_port;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
              set $up_wp_http "wp-http:9000";
              proxy_pass http://$up_wp_http$request_uri;
        }
}
server {
        listen HTML_PORT;
        server_name _;

        location / {
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
              set $up_app_html "app-html:8000";
              proxy_pass http://$up_app_html$request_uri;
        }
}

#######################WorkPlus-Office#######################
map $http_host $this_host {
    "" $host;
    default $http_host;
}
map $http_x_forwarded_proto $the_scheme {
    default $http_x_forwarded_proto;
    "" $scheme;
}
map $http_x_forwarded_host $the_host {
    default $http_x_forwarded_host;
    "" $this_host;
}
map $http_upgrade $proxy_connection {
    default upgrade;
    "" close;
}
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header X-Forwarded-Host $the_host;
proxy_set_header X-Forwarded-Proto $the_scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

server {
        listen DOCS_PORT;
        server_name _;

        ##DOCS端口根路径转发到 collabora 在线文档服务
        location / {
              set $up_app_collabora "app-collabora:9980";
              proxy_pass http://$up_app_collabora$request_uri;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection $proxy_connection;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Proto $scheme;
              proxy_set_header X-Forwarded-Uri $request_uri;
              proxy_set_header X-Forwarded-Ssl on;
        }
        location /welcome/ {
            if ($http_user_agent !~ ^workplus) {
                return 403;
            }
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document$request_uri;
        }
        location /example/ {
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document$request_uri;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        location /web-apps/ {
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document$request_uri;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        location /cache/ {
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document$request_uri;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        location ~ ^/[7-9]\.[0-9]\.[0-9]-[a-zA-Z0-9]+/ {
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        location ~ ^/[1-9][0-9]\.[0-9]\.[0-9]-[a-zA-Z0-9]+/ {
            proxy_pass http://172.16.32.13:9991;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

#######################WorkPlus-Meet#######################
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
        listen MEET_PORT ssl;
        listen 9922;
        server_name _;

        ssl_certificate /etc/nginx/certs/certs.pem;
        ssl_certificate_key /etc/nginx/certs/certs.key;
        ssl_protocols TLSv1.2;

        location / {
              set $up_meet "LANIP:9980";
              proxy_pass http://$up_meet$request_uri;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "$connection_upgrade";
        }
}
EOF
/bin/sed -i "s@DASH_PORT@${DASH_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@HTTP_PORT@${HTTP_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@HTML_PORT@${HTML_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@DOCS_PORT@${DOCS_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@MEET_PORT@${MEET_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@UDPS_PORT@${UDPS_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s/LANIP/${LANIP}/g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
fi
fi

if [[ "${url_prefix}" == "https" ]];then
if ! file_exists ${WP_DIR}/nginx/nginx.conf; then
prepare_nginx_config_path "${WP_DIR}/nginx/nginx.conf" || exit 1
cat > ${WP_DIR}/nginx/nginx.conf << "EOF"
user  nginx;
worker_processes  auto;
error_log  /var/log/nginx/error.log warn;
pid   /var/run/nginx.pid;
worker_rlimit_nofile 65535;
events {
    worker_connections  65535;
}

http {
    resolver 127.0.0.11 valid=10s ipv6=off;
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
        '$status $body_bytes_sent "$http_referer" '
        '"$http_user_agent" "$http_x_forwarded_for" '
        'upstream_response_time $upstream_response_time request_time $request_time ';

    access_log  /var/log/nginx/access.log main;

    map $http_upgrade $connection_upgrade {
            default upgrade;
            '' close;
    }

    include       /etc/nginx/conf.d/*.conf;
    include       /etc/nginx/mime.types;
    default_type  application/octet-stream;
    server_tokens off;
    charset UTF-8;

    limit_conn_zone  $binary_remote_addr  zone=one:10m;
    limit_conn_log_level notice;

    types_hash_max_size 2048;
    client_max_body_size 0;
    client_header_buffer_size 128k;
    client_body_buffer_size 1m;
    large_client_header_buffers 4 64k;

    proxy_headers_hash_max_size 1024;
    proxy_headers_hash_bucket_size 128;
    proxy_max_temp_file_size 5120m;

    sendfile on;
    tcp_nopush on;
    tcp_nodelay on;

    keepalive_timeout   65;
    keepalive_requests  10000;
    send_timeout        10;

    fastcgi_connect_timeout 300;
    fastcgi_send_timeout 300;
    fastcgi_read_timeout 300;
    fastcgi_buffer_size 64k;
    fastcgi_buffers 4 64k;
    fastcgi_busy_buffers_size 128k;
    fastcgi_temp_file_write_size 128k;

    gzip  on;
    gzip_min_length 1k;
    gzip_buffers 4 32k;
    gzip_http_version 1.1;
    gzip_comp_level 3;
    gzip_types text/plain application/javascript application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png application/json;
    gzip_disable "MSIE[1-6]";
    gzip_vary on;

    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $remote_addr;
    proxy_set_header X-Forwarded-Proto https;
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Port $server_port;
    proxy_connect_timeout 60;
    proxy_send_timeout 120;
    proxy_read_timeout 120;
    proxy_buffering on;
    proxy_buffer_size 32k;
    proxy_buffers 16 32k;
    proxy_busy_buffers_size 64k;
    proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
}

stream {
        resolver 127.0.0.11 valid=10s ipv6=off;
        log_format proxy '$remote_addr [$time_local] '
        '$protocol $status $bytes_sent $bytes_received '
        '$session_time "$upstream_addr" '
        '"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

        access_log  /var/log/nginx/stream.log  proxy;
        open_log_file_cache off;

        upstream im-mb {
                server 127.0.0.1:1;
        }
        upstream im-pc {
                server 127.0.0.1:1;
        }

        server {
                listen MBIM_PORT;
                set $up_im_mb "wp-server:8120";
                proxy_pass $up_im_mb;
        }
        server {
                listen PCIM_PORT;
                set $up_im_pc "wp-server:8121";
                proxy_pass $up_im_pc;
        }
}
EOF
/bin/sed -i "s@MBIM_PORT@${MBIM_PORT}@g" ${WP_DIR}/nginx/nginx.conf > /dev/null 2>&1
/bin/sed -i "s@PCIM_PORT@${PCIM_PORT}@g" ${WP_DIR}/nginx/nginx.conf > /dev/null 2>&1
fi
if [ "${IM_SSL}" == "on" ];then
   sed -i "s/listen ${PCIM_PORT};/listen ${PCIM_PORT} ssl;/g" ${WP_DIR}/nginx/nginx.conf
fi

if ! file_exists ${WP_DIR}/nginx/default.conf; then
prepare_nginx_config_path "${WP_DIR}/nginx/default.conf" || exit 1
cat > ${WP_DIR}/nginx/default.conf << "EOF"
server {
        listen DASH_PORT ssl;
        listen 9914;
        server_name _;

        ssl_certificate "/etc/nginx/certs/certs.pem";
        ssl_certificate_key "/etc/nginx/certs/certs.key";
        ssl_protocols TLSv1.2;

        location / {
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for:$remote_port;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
              set $up_wp_dash "wp-dash:9000";
              proxy_pass http://$up_wp_dash$request_uri;
        }
}
server {
        listen HTTP_PORT ssl;
        listen 9913;
        server_name _;

        ssl_certificate "/etc/nginx/certs/certs.pem";
        ssl_certificate_key "/etc/nginx/certs/certs.key";
        ssl_protocols TLSv1.2;

        location / {
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for:$remote_port;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
              set $up_wp_http "wp-http:9000";
              proxy_pass http://$up_wp_http$request_uri;
        }
}
server {
        listen HTML_PORT ssl;
        server_name _;

        ssl_certificate "/etc/nginx/certs/certs.pem";
        ssl_certificate_key "/etc/nginx/certs/certs.key";
        ssl_protocols TLSv1.2;

        location / {
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_http_version 1.1;
              proxy_set_header Connection "";
              set $up_app_html "app-html:8000";
              proxy_pass http://$up_app_html$request_uri;
        }
}

#######################WorkPlus-Office#######################
map $http_host $this_host {
    "" $host;
    default $http_host;
}
map $http_x_forwarded_proto $the_scheme {
    default $http_x_forwarded_proto;
    "" $scheme;
}
map $http_x_forwarded_host $the_host {
    default $http_x_forwarded_host;
    "" $this_host;
}
map $http_upgrade $proxy_connection {
    default upgrade;
    "" close;
}
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $proxy_connection;
proxy_set_header X-Forwarded-Host $the_host;
proxy_set_header X-Forwarded-Proto $the_scheme;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;

server {
        listen DOCS_PORT ssl;
        server_name _;

        ssl_certificate "/etc/nginx/certs/certs.pem";
        ssl_certificate_key "/etc/nginx/certs/certs.key";
        ssl_protocols TLSv1.2;

        ##DOCS端口根路径转发到 collabora 在线文档服务
        location / {
              set $up_app_collabora "app-collabora:9980";
              proxy_pass http://$up_app_collabora$request_uri;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection $proxy_connection;
              proxy_set_header Host $host;
              proxy_set_header X-Real-IP $remote_addr;
              proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
              proxy_set_header X-Forwarded-Proto $scheme;
              proxy_set_header X-Forwarded-Uri $request_uri;
              proxy_set_header X-Forwarded-Ssl on;
        }
        location /welcome/ {
            if ($http_user_agent !~ ^workplus) {
                return 403;
            }
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document$request_uri;
        }
        location /example/ {
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document$request_uri;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        location /web-apps/ {
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document$request_uri;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        location /cache/ {
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document$request_uri;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        ##支持onlyofficev7-9版本
        location ~ ^/[7-9]\.[0-9]\.[0-9]-[a-zA-Z0-9]+/ {
            set $up_app_document "app-document:80";
            proxy_pass http://$up_app_document;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
        ##支持onlyofficev10以上版本
        location ~ ^/[1-9][0-9]\.[0-9]\.[0-9]-[a-zA-Z0-9]+/ {
            proxy_pass http://172.16.32.13:9991;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection $proxy_connection;
            proxy_set_header X-Forwarded-Host $the_host;
            proxy_set_header X-Forwarded-Proto $the_scheme;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        }
}

#######################WorkPlus-Meet#######################
map $http_upgrade $connection_upgrade {
    default upgrade;
    '' close;
}

server {
        listen MEET_PORT ssl;
        server_name _;

        ssl_certificate /etc/nginx/certs/certs.pem;
        ssl_certificate_key /etc/nginx/certs/certs.key;
        ssl_protocols TLSv1.2;

        location / {
              set $up_meet "LANIP:9980";
              proxy_pass http://$up_meet$request_uri;
              proxy_http_version 1.1;
              proxy_set_header Upgrade $http_upgrade;
              proxy_set_header Connection "$connection_upgrade";
        }
}
EOF
/bin/sed -i "s@DASH_PORT@${DASH_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@HTTP_PORT@${HTTP_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@HTML_PORT@${HTML_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@DOCS_PORT@${DOCS_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@MEET_PORT@${MEET_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s@UDPS_PORT@${UDPS_PORT}@g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
/bin/sed -i "s/LANIP/${LANIP}/g" ${WP_DIR}/nginx/default.conf > /dev/null 2>&1
fi
fi

if ! file_exists ${WP_DIR}/nginx/certs/certs.pem; then
cat > ${WP_DIR}/nginx/certs/certs.pem << EOF
-----BEGIN CERTIFICATE-----
MIIEBzCCAu+gAwIBAgIUHycb7F9YieqGFxjbuOhgez22CLwwDQYJKoZIhvcNAQEL
BQAwgZExCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhTSEFOR0hBSTERMA8GA1UEBwwI
U0hBTkdIQUkxDjAMBgNVBAoMBVNFUFJPMQ4wDAYDVQQLDAVTRVBSTzEZMBcGA1UE
AwwQc2Vwcm8uZG9tYWluLmNvbTEhMB8GCSqGSIb3DQEJARYSc3VwcG9ydEBkb21h
aW4uY29tMCAXDTI0MTExMTA3MDkwNloYDzIxMjQxMDE4MDcwOTA2WjCBkTELMAkG
A1UEBhMCQ04xETAPBgNVBAgMCFNIQU5HSEFJMREwDwYDVQQHDAhTSEFOR0hBSTEO
MAwGA1UECgwFU0VQUk8xDjAMBgNVBAsMBVNFUFJPMRkwFwYDVQQDDBBzZXByby5k
b21haW4uY29tMSEwHwYJKoZIhvcNAQkBFhJzdXBwb3J0QGRvbWFpbi5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLGTeuA6qeqCZCCbpU5KKv4qD9
BoRlCGXxCNkFpIV26b/V/7M1hLN0+Y9bURe/4Ja947B2rWw2B/4B4fZ97ORBN+PH
Db6PsDTWvJch15u6c5Uy6eCzRSw7TQ5HbByuAwau+9M5t2pli8apHpvBFP33hh8H
FJJO/x9acV8rRejirFElvmXGFjeS9S0Kjyu/LnsTAscGqkvVUVTAjqB9FI/gRhX4
KpT6uyMjC3q66Wzyu+zoQldMcaO2lpwHxxvQnAFmYgoCIQQFJWW1GtjsbdfqnJtE
dsM7BYhZqnpQq8YFpT4vRy7P7e8srPvVMOuEU4w4CKG/2rC2S61pBnvLphIJAgMB
AAGjUzBRMB0GA1UdDgQWBBRsNMlXZbnL6pLx9Cf6yJZskNMxjDAfBgNVHSMEGDAW
gBRsNMlXZbnL6pLx9Cf6yJZskNMxjDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
DQEBCwUAA4IBAQCY67YUh2XQXfzi8e1IomoEn/981i74RWrZW8V+TZoYpafx+NTo
JxOSbdUgKhYUdiQJTKNR0PBDSJMwhvic5SWI+K8nyc1+EAuCRD1Rc+v1Oo1Zhozc
jXedRh6ecYsylnZRwLUHp9DXEGCp4F4Fx7cGbDDuVZoQfL/sjNC/A/VyrChm2Qbr
ktO0E4x8RlN9WR60ZGqKFythd9e9SiIiKHBPiTDKnnu+yr8i1DqloXHdl/aUi1gf
T/i8FzAD4O2X6f3xxTA/3ccjrG9KU0WTVpzXLmXUjpyeC9RulLBz4jRsXWx3S1i5
D6d8jsFXVz9LOflMZ2spDT6TRa4DWOxzs6yC
-----END CERTIFICATE-----
EOF
fi

if ! file_exists ${WP_DIR}/nginx/certs/certs.key; then
cat > ${WP_DIR}/nginx/certs/certs.key << EOF
-----BEGIN PRIVATE KEY-----
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDLGTeuA6qeqCZC
CbpU5KKv4qD9BoRlCGXxCNkFpIV26b/V/7M1hLN0+Y9bURe/4Ja947B2rWw2B/4B
4fZ97ORBN+PHDb6PsDTWvJch15u6c5Uy6eCzRSw7TQ5HbByuAwau+9M5t2pli8ap
HpvBFP33hh8HFJJO/x9acV8rRejirFElvmXGFjeS9S0Kjyu/LnsTAscGqkvVUVTA
jqB9FI/gRhX4KpT6uyMjC3q66Wzyu+zoQldMcaO2lpwHxxvQnAFmYgoCIQQFJWW1
GtjsbdfqnJtEdsM7BYhZqnpQq8YFpT4vRy7P7e8srPvVMOuEU4w4CKG/2rC2S61p
BnvLphIJAgMBAAECggEAMSQD3d3TPZovz5Cs/fdoCaiLDU2zYQK8L6rVX9Ej3dbG
7M92m/9ksGvlrNGdLnb34jAiNUTWxuf+JJR44JUd0U3llfcUYY3f6wkshCq36lAn
DG+cR6P4BM0rJErbUZs31cTmobNoUfOU+LyIMRqULHzOKxdmIykFfAusXDsJEzbx
/SFsh5C14tS16kUDk9tmg50LzHykyKGU3s3Vnb4vZObk6o+gpWe4GrEE3fKyzrCw
RqKjdsSs1zgw8VsQ5t5lYpUsPn0rHHQcLGeJWDUCk/ZQ1xP7Q8n8BHkq5nkpD9CY
VIdi0poTRweB5ptx+TxGLaFHGRxhandaJOToYgw3gQKBgQDnFu67rytn4S6nZVg1
n+3UUN5OOvWeh1sOHA2cIKRbQfpETHhgdIbmAo7Ln3E0lrHoknm2e48t6tGjysNz
gkYd4zNFHv/T+57/j+cRVfTEXjDqctOCrv54VV1GKiXaqcfsRgeXvqoyEma3fev3
J+UfZEr7cnfr3XABo7PQKRAdeQKBgQDg/dpfodnigos2R8XO/Ysq3erxbvMeZA7C
PK9P5BHXB0tBxO/ffeJEGDgcNgBu+CmcopVeU8OdXglB5VnEVWLAakNW91oN5exb
MPGf2D0zXo5z2gkd+Dj73IC/E/CoImmci08yKnOLOzI3hT4h3F7voTOrNDFoRzll
Fk1GFpbFEQKBgQCkB8QnltxRnSZXjflB/yZ6+XgCwZkNEPkSF9mVRBpF6JwzlLAx
jyUd6Rzg7mkVsg3QjwA0BpqINlDeWZPIzuTkXBxNaQagus+Oid+zj3bxWAaStDTs
Yzifw8A0iMBb6P3O+Zp0HNOEPUmJ36j5w+jAEpmiyArVclYJ4+BD1pHoyQKBgQCB
rS6JAhM//3fXYES9idsFaQS6BPWxZYAwKaPtywkRQ433qVeMG9Um5EKq1+EmFHh/
ZCHtTSAo+oMhbNxxUblqJ5UKceSAsC2rXalWNN8JVY2LbnbkxCWr3KqD9y006yit
5olN47PW4taNs4ldINPDD8lk+t8jODH3doQxSmG50QKBgQC8prk8GjJoVOXmZeEb
Kz1nPB5Vdhqt+4zwnreYg2GUXVjTmf2O/FNz48b5hLGzBPgRXB0/pL1EJcSAvKgQ
AHrrJlo6ssVPXJRVyZ1O1XXPWmJhs556FNvoD3KCiEsKWy/om1dgymZw7W1G3tn9
HtZMyzz7eblbcgzCfKPCrWzldQ==
-----END PRIVATE KEY-----
EOF
fi
}

get_container_id () {
    CONTAINER_NAME=$1;
    if [[ -z ${CONTAINER_NAME} ]]; then
        echo "Empty container name"
        exit 1;
    fi
    CONTAINER_ID="";
    CONTAINER_EXIST=$(docker ps -aqf "name=$CONTAINER_NAME");

    if [[ -n ${CONTAINER_EXIST} ]]; then
        CONTAINER_ID=$(docker inspect --format='{{.Id}}' ${CONTAINER_NAME});
    fi
    echo "$CONTAINER_ID"
}

get_container_ip () {
    CONTAINER_NAME=$1;
    if [[ -z ${CONTAINER_NAME} ]]; then
        echo "Empty container name"
        exit 1;
    fi
    CONTAINER_IP="";
    CONTAINER_EXIST=$(docker ps -aqf "name=$CONTAINER_NAME");
    if [[ -n ${CONTAINER_EXIST} ]]; then
        CONTAINER_IP=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' ${CONTAINER_NAME});
    fi
    echo "$CONTAINER_IP"
}

verify_download_file () {
    local target_file="$1"
    [[ -s "${target_file}" ]] || return 1
    case "${target_file}" in
        *.tgz|*.tar.gz)
            tar -tzf "${target_file}" >/dev/null 2>&1
            ;;
        *)
            return 0
            ;;
    esac
}

download_file_retry () {
    local download_url="$1"
    local target_file="$2"
    local package_name="${3:-下载文件}"
    local temp_file="${target_file}.part"
    local retry_max=10
    local retry_interval=10
    local attempt

    if verify_download_file "${target_file}"; then
        echo "检测到完整的${package_name}, 跳过重复下载" >>${platform_msg_log} 2>&1
        return 0
    fi
    if [[ -e "${target_file}" ]]; then
        echo "[WARN] 检测到不完整的${package_name}, 已清理并重新下载" | tee -a ${platform_err_log}
        /bin/rm -f "${target_file}"
    fi
    for ((attempt = 1; attempt <= retry_max; attempt++)); do
        /bin/rm -f "${temp_file}"
        echo "[WARN] 正在下载${package_name}, 第${attempt}/${retry_max}次尝试..." | tee -a ${platform_err_log}
        if curl -fL --connect-timeout 15 --max-time 900 -o "${temp_file}" "${download_url}" >>${platform_err_log} 2>&1; then
            if verify_download_file "${temp_file}"; then
                /bin/mv -f "${temp_file}" "${target_file}"
                echo "下载${package_name}成功, 完整性校验通过" >>${platform_msg_log} 2>&1
                return 0
            fi
            echo "[WARN] ${package_name}下载内容不完整, 将重新下载" | tee -a ${platform_err_log}
        else
            echo "[WARN] ${package_name}下载失败, 可能是DNS解析或网络临时异常" | tee -a ${platform_err_log}
        fi
        /bin/rm -f "${temp_file}"
        if [[ ${attempt} -lt ${retry_max} ]]; then
            echo "[WARN] ${retry_interval}秒后自动重试, 请勿中断安装..." | tee -a ${platform_err_log}
            sleep "${retry_interval}"
        fi
    done
    echo "[ERROR] ${package_name}连续${retry_max}次下载失败, 详情见: ${platform_err_log}" | tee -a ${platform_err_log}
    return 1
}

download_image () {
    local server_image_name="$1"
    local server_container_name="$2"
    local retry_max=5
    local retry_interval=10
    local attempt
    local pull_rc

    if [[ -z "${server_image_name}" ]]; then
        echo "镜像地址和镜像版本为空, 请重新输入" | tee -a ${platform_err_log}
        exit 1
    fi
    if docker image inspect "${server_image_name}" >/dev/null 2>&1; then
        echo "服务器已存在${server_container_name}镜像资源" >>${platform_msg_log} 2>&1
        return 0
    fi
    echo -e "\n开始下载${server_container_name}镜像资源" | tee -a ${platform_msg_log}
    for ((attempt = 1; attempt <= retry_max; attempt++)); do
        docker pull "${server_image_name}" 2>&1 | tee -a ${platform_msg_log}
        pull_rc=${PIPESTATUS[0]}
        if [[ ${pull_rc} -eq 0 ]]; then
            echo "下载${server_container_name}镜像资源完成" >>${platform_msg_log} 2>&1
            return 0
        fi
        echo "[WARN] ${server_container_name}镜像下载失败, 第${attempt}/${retry_max}次" | tee -a ${platform_err_log}
        if [[ ${attempt} -lt ${retry_max} ]]; then
            echo "[WARN] ${retry_interval}秒后自动重试镜像下载..." | tee -a ${platform_err_log}
            sleep "${retry_interval}"
        fi
    done
    echo "[ERROR] ${server_container_name}镜像连续${retry_max}次下载失败, 请检查网络后重新安装" | tee -a ${platform_err_log}
    exit 1
}

install_jq () {
    if [[ "${MACH}" == "x86_64" ]]; then
       if ! command_exists jq; then
          ping -c 2 -i 1 mirrors.aliyun.com > /dev/null 2>&1
          if [ $? -eq 0 ]; then
            curl -o /usr/bin/jq http://w6s-binaries.oss-cn-hangzhou.aliyuncs.com/software/jq-linux64 >> ${platform_err_log} 2>&1
            if [ -f /usr/bin/jq ]; then
               chmod +x /usr/bin/jq
               jq --version >> ${platform_msg_log} 2>&1
               if [ $? -eq 0 ]; then
                  echo -e "\n安装jq命令成功" >> ${platform_msg_log} 2>&1
               else
                  echo -e "\njq安装包下载不完整, 请确保网络连接正常, 可再次尝试安装"|tee -a ${platform_err_log}
                  echo "请查看日志文件获取失败原因, 日志文件:${platform_err_log}"
               fi
            else
               echo -e "\njq安装包下载失败, 请确保网络连接正常, 可再次尝试安装"|tee -a ${platform_err_log}
               echo "请查看日志文件获取失败原因, 志文件:${platform_err_log}"
            fi
          else
            echo "离线环境, 跳过安装" >> ${platform_msg_log} 2>&1
          fi
       fi
    fi

    if [[ "${MACH}" == "aarch64" ]]; then
       if ! command_exists jq; then
          ping -c 2 -i 1 mirrors.aliyun.com > /dev/null 2>&1
          if [ $? -eq 0 ]; then
            curl -o /usr/bin/jq http://w6s-binaries.oss-cn-hangzhou.aliyuncs.com/software/jq-linux-arm64 >> ${platform_err_log} 2>&1
            if [ -f /usr/bin/jq ]; then
               chmod +x /usr/bin/jq
               jq --version >> ${platform_msg_log} 2>&1
               if [ $? -eq 0 ]; then
                  echo -e "\n安装jq命令成功" >> ${platform_msg_log} 2>&1
               else
                  echo -e "\njq安装包下载不完整, 请确保网络连接正常, 可再次尝试安装"|tee -a ${platform_err_log}
                  echo "请查看日志文件获取失败原因, 日志文件:${platform_err_log}"
               fi
            else
               echo -e "\njq安装包下载失败, 请确保网络连接正常, 可再次尝试安装"|tee -a ${platform_err_log}
               echo "请查看日志文件获取失败原因, 日志文件:${platform_err_log}"
            fi
          else
            echo "离线环境, 跳过安装" >> ${platform_msg_log} 2>&1
          fi
       fi
    fi
}

install_xxd () {
    if ! command_exists xxd; then
       ping -c 2 -i 1 mirrors.aliyun.com > /dev/null 2>&1
       if [ $? -eq 0 ]; then
          echo -e "\ninstall command xxd - waiting for it ..."|tee -a ${platform_msg_log}
          if command_exists apt; then
             apt update -y > /dev/null 2>&1
             apt install -y xxd >> ${platform_msg_log} 2>&1
          elif command_exists yum; then
             yum install -y vim-common >> ${platform_msg_log} 2>&1
          fi
       else
          echo "离线环境, 无法安装xxd应用" >> ${platform_msg_log} 2>&1
       fi
    fi

    if ! command_exists xxd; then
        echo "在线安装xxd命令失败, 脚本退出, 请确保网络连通正常再重新安装"|tee -a ${platform_err_log}
        echo "install command xxd failed, script exits"|tee -a ${platform_err_log}
        exit 1;
    fi
}

install_curl () {
    if ! command_exists curl; then
       ping -c 2 -i 1 mirrors.aliyun.com > /dev/null 2>&1
       if [ $? -eq 0 ]; then
          echo -e "\ninstall command curl - waiting for it ..."|tee -a ${platform_msg_log}
          if command_exists apt; then
             apt update -y > /dev/null 2>&1
             apt install -y curl >> ${platform_msg_log} 2>&1
          elif command_exists yum; then
             yum install -y curl >> ${platform_msg_log} 2>&1
          fi
       else
          echo "离线环境, 无法安装curl应用" >> ${platform_msg_log} 2>&1
       fi
    fi

    if ! command_exists curl; then
        echo "在线安装curl命令失败, 脚本退出, 请确保网络连通正常再重新安装"|tee -a ${platform_err_log}
        echo "install command curl failed, script exits"|tee -a ${platform_err_log}
        exit 1;
    fi
}

install_iptables () {
    if ! command_exists iptables; then
       ping -c 2 -i 1 mirrors.aliyun.com > /dev/null 2>&1
       if [ $? -eq 0 ]; then
          echo -e "\ninstall command iptables - waiting for it ..."|tee -a ${platform_msg_log}
          if command_exists apt; then
             apt update -y > /dev/null 2>&1
             apt install -y iptables >> ${platform_msg_log} 2>&1
          elif command_exists yum; then
             yum install -y iptables-services >> ${platform_msg_log} 2>&1
          fi
       else
          echo "离线环境, 无法安装iptables应用" >> ${platform_msg_log} 2>&1
       fi
    fi

    if ! command_exists iptables; then
        echo "安装本产品必须依赖iptables工具, 但本机无法在线安装iptables软件包"|tee -a ${platform_err_log}
        echo "请开放服务器访问互联网权限, 安装脚本会自动安装iptables软件包"|tee -a ${platform_err_log}
        echo "如服务器无法访问互联网, 请更换带Server软件包的操作系统重新部署"|tee -a ${platform_err_log}
        echo "install command iptables failed, script exits"|tee -a ${platform_err_log}
        exit 1;
    fi
}

install_tar () {
    if ! command_exists tar; then
       ping -c 2 -i 1 mirrors.aliyun.com > /dev/null 2>&1
       if [ $? -eq 0 ]; then
          echo -e "\ninstall command tar - waiting for it ..."|tee -a ${platform_msg_log}
          if command_exists apt; then
             apt update -y > /dev/null 2>&1
             apt install -y tar >> ${platform_msg_log} 2>&1
          elif command_exists yum; then
             yum install -y tar >> ${platform_msg_log} 2>&1
          fi
       else
          echo "离线环境, 无法安装tar应用" >> ${platform_msg_log} 2>&1
       fi
    fi

    if ! command_exists tar; then
        echo "安装本产品必须依赖tar工具, 但本机无法在线安装tar软件包"|tee -a ${platform_err_log}
        echo "请开放服务器访问互联网权限, 安装脚本会自动安装tar软件包"|tee -a ${platform_err_log}
        echo "如服务器无法访问互联网, 请更换带Server软件包的操作系统重新部署"|tee -a ${platform_err_log}
        echo "install command iptables failed, script exits"|tee -a ${platform_err_log}
        exit 1;
    fi
}

install_ntpdate () {
    if ! command_exists ntpdate; then
       ping -c 2 -i 1 mirrors.aliyun.com > /dev/null 2>&1
       if [ $? -eq 0 ]; then
          echo -e "\ninstall command ntpdate - waiting for it ..." >> ${platform_msg_log} 2>&1
          if command_exists apt; then
             apt update -y > /dev/null 2>&1
             apt install -y ntpdate >> ${platform_msg_log} 2>&1
          elif command_exists yum; then
             yum install -y ntpdate >> ${platform_msg_log} 2>&1
          fi
       else
          echo "离线环境, 无法安装ntpdate应用" >> ${platform_msg_log} 2>&1
       fi
    fi

    if ! command_exists ntpdate; then
        echo "install command ntpdate failed, script continue" >> ${platform_err_log} 2>&1
    fi
}

update_time () {
    rm -f /etc/localtime
    ln -sf /usr/share/zoneinfo/Asia/Shanghai /etc/localtime

    if ! command_exists ntpdate; then
        install_ntpdate
    fi

    if command_exists chronyc; then
       sed -i '/stdtime.gov.hk/d' /etc/chrony.conf > /dev/null 2>&1
       sed -i '1i server stdtime.gov.hk iburst' /etc/chrony.conf > /dev/null 2>&1
       systemctl restart chronyd > /dev/null 2>&1
    else
       if command_exists ntpdate; then
          if command_exists yum; then
             setenforce 0 > /dev/null 2>&1
             sed -i "s/SELINUX=.*/SELINUX=disabled/" /etc/selinux/config > /dev/null 2>&1
             ntpdate stdtime.gov.hk > /dev/null 2>&1
          else
             ntpdate stdtime.gov.hk > /dev/null 2>&1
          fi
       else
          echo "Command ntpdate or chronyc not found, Please confirm the system time is Beijing time"|tee -a ${platform_err_log}
          echo ""
      fi
    fi
}

sleep_time () {
    count_time=$1
    start_time=$(date +%s)
    while true; do
      current_time=$(date +%s)
      elapsed_time=$((current_time - start_time))
      if [ "$elapsed_time" -ge ${count_time} ]; then
           break
      fi
      echo -n "."
      sleep 1
    done
    echo
}

#check_selinux () {
#    if command_exists sestatus; then
#       if [[ "$(/usr/sbin/sestatus -v|awk '{print $NF}'|head -n 1)" == "enabled" ]];then
#          echo -e "\033[1;31m系统当前selinux策略为启用状态, 可能导致服务无法启动, 需要把此策略设置为禁用.\033[0m"|tee -a ${platform_err_log}
#          echo -e "\033[1;31m请执行以下脚本命令设置为禁用, 设置后需重启服务器生效, 请重启完成后再尝试安装.\033[0m"|tee -a ${platform_err_log}
#          echo -e "\033[1;31m如需了解更多selinux知识, 请参考百度百科或者查阅RedHat官网文档.\033[0m"|tee -a ${platform_err_log}
#          echo ""
#          echo -e "步骤1. 执行命令: sed -i 's/SELINUX=.*/SELINUX=disabled/g' /etc/selinux/config; ##设置禁用."
#          echo -e "步骤2. 执行命令: reboot; ##重启服务器使设置生效."
#          echo ""
#          exit 1;
#       fi
#    fi
#}

check_network () {
    local retry_max=5
    local retry_interval=5
    local attempt
    local response_code

    check_network_code=000
    for ((attempt = 1; attempt <= retry_max; attempt++)); do
        response_code=$(curl -k -m 15 -o /dev/null -s -w "%{http_code}" \
            https://w6s-docker.oss-cn-shenzhen.aliyuncs.com/install-se.sh 2>>${platform_err_log})
        if [[ -n "${response_code}" && "${response_code}" != "000" ]]; then
            check_network_code=200
            echo "网络探测成功, HTTP状态码: ${response_code}" >>${platform_msg_log} 2>&1
            return 0
        fi
        echo "[WARN] 网络探测失败, 第${attempt}/${retry_max}次尝试" | tee -a ${platform_err_log}
        if [[ ${attempt} -lt ${retry_max} ]]; then
            echo "[WARN] ${retry_interval}秒后重新探测网络, 请勿中断安装..." | tee -a ${platform_err_log}
            sleep "${retry_interval}"
        fi
    done
    echo "[WARN] 连续${retry_max}次网络探测失败, 将按离线环境继续处理" | tee -a ${platform_err_log}
}

check_runc () {
    if ! command -v runc &> /dev/null; then
        echo -e "\n服务器当前未安装runc应用" >> ${platform_msg_log} 2>&1
        return 0;
    else
        echo -e "\n服务器当前已安装runc应用" >> ${platform_msg_log} 2>&1
    fi

    RUNC_PATH=$(command -v runc)
    VERSION=$(runc -v 2>/dev/null | grep -oP 'runc version \K[0-9]+\.[0-9]+\.[0-9]+')

    if [ -z "$VERSION" ]; then
        echo -e "\n检测到已存在runc应用, 但无法获取runc版本" >> ${platform_err_log} 2>&1
        return 0;
    fi
    echo "当前已安装runc版本: $VERSION" >> ${platform_msg_log} 2>&1

    ##定义卸载runc执行函数
    uninstall_runc () {
        # 根据安装方式选择卸载方法
        if [[ "$RUNC_PATH" == /usr/local/* ]]; then
            # 源码编译安装
            echo "检测到runc为二进制文件, 直接删除: $RUNC_PATH" >> ${platform_msg_log} 2>&1
            rm -f "$RUNC_PATH"
        elif [[ "$RUNC_PATH" == /snap/* ]]; then
            # snap 安装
            snap remove runc 2>/dev/null || true
        elif [[ "$RUNC_PATH" == /usr/bin/runc ]] && command -v apt &> /dev/null; then
            # apt 安装
            apt remove -y runc 2>/dev/null || true
        elif [[ "$RUNC_PATH" == /usr/bin/runc ]] && command -v yum &> /dev/null; then
            # yum 安装
            yum remove -y runc 2>/dev/null || true
        elif [[ "$RUNC_PATH" == /usr/bin/runc ]] && command -v dnf &> /dev/null; then
            # dnf 安装
            dnf remove -y runc 2>/dev/null || true
        else
            # 默认直接删除
            echo "检测到runc在自定义安装目录, 直接删除: $RUNC_PATH" >> ${platform_msg_log} 2>&1
            rm -f "$RUNC_PATH" 2>/dev/null || true
        fi

        # 删除可能的符号链接
        for link in /usr/bin/runc /usr/local/bin/runc /bin/runc; do
            if [ -L "$link" ]; then
               rm -f "$link" 2>/dev/null || true
            fi
        done

        ##验证卸载结果
        if ! command -v runc &> /dev/null; then
           echo "卸载runc执行成功" >> ${platform_msg_log} 2>&1
        else
           echo "卸载runc执行失败, 请手动处理" >> ${platform_msg_log} 2>&1
           return 0;
        fi
    }

    IFS='.' read -r -a VER_ARRAY <<< "$VERSION"
    MAJOR=${VER_ARRAY[0]}
    MINOR=${VER_ARRAY[1]}
    PATCH=${VER_ARRAY[2]}

    ##检查是否低于1.1.7(CentOS7环境runc版本太低或者太高都不兼容)
    if [ "$MAJOR" -lt 1 ] || \
       [ "$MAJOR" -eq 1 -a "$MINOR" -lt 1 ] || \
       [ "$MAJOR" -eq 1 -a "$MINOR" -eq 1 -a "$PATCH" -lt 7 ]; then
        echo "警告: 当前runc版本${VERSION}不符合要求(<1.1.7), 开始自动卸载" >> ${platform_msg_log} 2>&1
        uninstall_runc
    else
        echo "当前runc版本$VERSION符合要求(>= 1.1.7), 脚本继续进行" >> ${platform_msg_log} 2>&1
    fi
}

check_docker () {
    CUR_FULL_VERSION=$(docker -v | cut -d ' ' -f3 | cut -d ',' -f1);
    CUR_VERSION=$(echo ${CUR_FULL_VERSION} | cut -d '-' -f1);
    CUR_EDITION=$(echo ${CUR_FULL_VERSION} | cut -d '-' -f2);

    if [[ "${CUR_EDITION}" == "ce" ]] || [[ "${CUR_EDITION}" == "ee" ]]; then
        return 0;
    fi

    if [[ "${CUR_VERSION}" != "${CUR_EDITION}" ]]; then
        echo "Unspecific docker version"|tee -a ${platform_err_log}
        exit 1;
    fi

    MIN_NUM_ARR=(23 0 0);  ##建议docker版本不低于23.0.0
    CUR_NUM_ARR=();

    CUR_STR_ARR=$(echo ${CUR_VERSION} | grep -Po "[0-9]+\.[0-9]+\.[0-9]+" | tr "." " ");

    for CUR_STR_ITEM in ${CUR_STR_ARR}
    do
        CUR_NUM_ARR=(${CUR_NUM_ARR[@]} ${CUR_STR_ITEM})
    done

    INDEX=0;

    while [[ ${INDEX} -lt 3 ]]; do
        if [[ ${CUR_NUM_ARR[INDEX]} -lt ${MIN_NUM_ARR[INDEX]} ]]; then
           echo ""
           echo -e "\033[1;33mDocker version: ${CUR_FULL_VERSION}\033[0m"|tee -a ${platform_err_log}
           echo ""
           echo -e "\033[1;31mDetected that a lower version of Docker has been installed.\033[0m"
           echo -e "\033[1;31mPlease uninstall it first or receive an upgrade to the latest version.\033[0m"
           echo ""
           echo -e "\033[1;31m检测到服务器已经安装较低版本的docker应用.\033[0m"|tee -a ${platform_err_log}
           echo -e "\033[1;31m请先将其关闭卸载, 当前脚本会自动安装较新的版本.\033[0m"|tee -a ${platform_err_log}
           echo -e "\033[1;31m如果本机已运行其它docker容器应用, 建议更换空白服务器部署.\033[0m"|tee -a ${platform_err_log}
           echo ""
           exit 1;
        elif [[ ${CUR_NUM_ARR[INDEX]} -gt ${MIN_NUM_ARR[INDEX]} ]]; then
           return 0;
        fi
        (( INDEX++ ))
    done
}

start_docker () {
    echo -e "\n记录docker版本信息: $(docker --version)" >> ${platform_msg_log} 2>&1
    echo -e "\n记录docker版本信息: $(docker --version)" >> ${platform_err_log} 2>&1
    docker ps 2>/dev/null | grep 'CONTAINER ID' >> /dev/null 2>&1
    if [ $? -ne 0 ];then
       echo "Docker服务状态异常, 正在尝试重启..."|tee -a ${platform_err_log}
       systemctl daemon-reload
       systemctl enable docker >> ${platform_err_log} 2>&1
       systemctl restart docker >> ${platform_err_log} 2>&1
       if [ $? -ne 0 ];then
          echo -e "\n\033[1;31m
          Docker进程状态检测失败, 请查看系统日志获取失败原因;
          Linux系统日志通常为/var/log/messages或/var/log/syslog;
          如无法确切定位启动失败原因, 请从以下几方面分析定位:
             1.docker配置文件错误;
             2.docker守护进程权限不足;
             3.服务器存储驱动问题;
             4.服务器内核版本太低或缺少必须模块(overlay/br_netfilter);
             5.SELinux/AppArmor安全限制;

          如无法定位问题原因, 请尝试重启服务器后再重试安装;
          如果重启后依然安装失败, 建议更换官网部署页面中推荐的操作系统重新部署.
          \033[0m"|tee -a ${platform_err_log}
          exit 1
       else
          echo "Docker服务重启成功"|tee -a ${platform_msg_log}
       fi
    else
       echo "Docker服务已安装且运行中" >> ${platform_msg_log} 2>&1
    fi
}

get_docker_binary_files () {
    ##X86架构
    if [[ "${MACH}" == "x86_64" ]]; then
        if [[ "${check_network_code}" == "000" ]]; then
           if ! file_exists /tmp/docker-${DOCKER_BINARY_VERSION}-amd64.tgz; then
              if ! file_exists "${OFFLINE_DIR}/packages-amd64/docker-${DOCKER_BINARY_VERSION}-amd64.tgz"; then
                 echo "找不到Docker离线安装包, 请检查目录temp_files/packages-amd64下是否存在docker-${DOCKER_BINARY_VERSION}-amd64.tgz"|tee -a ${platform_err_log}
                 echo "如果缺失docker-${DOCKER_BINARY_VERSION}-amd64.tgz文件, 请按照官方文档重新下载离线包进行安装"|tee -a ${platform_err_log}
                 exit 1;
              else
                 echo "install docker from local package - waiting for it ..."
                 /bin/cp -ra "${OFFLINE_DIR}/packages-amd64/docker-${DOCKER_BINARY_VERSION}-amd64.tgz" /tmp/
              fi
           fi
           if ! file_exists /usr/bin/docker-compose; then
              if ! file_exists "${OFFLINE_DIR}/packages-amd64/docker-compose"; then
                 echo "找不到Docker-compose离线安装包, 请检查目录temp_files/packages-amd64是否存在docker-compose"|tee -a ${platform_err_log}
                 echo "如果缺失Docker-compose文件, 请按照官方文档重新下载离线包进行安装"|tee -a ${platform_err_log}
                 exit 1;
              else
                 /bin/cp -ra "${OFFLINE_DIR}/packages-amd64/docker-compose" /usr/bin/
                 chmod +x /usr/bin/docker-compose
              fi
           fi
        fi
        if [[ "${check_network_code}" == "200" ]]; then
           if ! file_exists /tmp/docker-${DOCKER_BINARY_VERSION}-amd64.tgz; then
              echo -e "\ninstall docker from internet package - waiting for it ..."|tee -a ${platform_msg_log}
              download_file_retry "${DOCKER_BINARY_AMD64}" "/tmp/docker-${DOCKER_BINARY_VERSION}-amd64.tgz" "Docker安装包"
              if [ $? -eq 0 ]; then
                 echo "下载docker安装包成功" >> ${platform_msg_log} 2>&1
              else
                 echo "下载docker安装包失败, 安装中断, 请确保网络连通正常再重新安装"|tee -a ${platform_err_log}
                 exit 1;
              fi
           fi
        fi

        /bin/rm -rf /tmp/docker-se > /dev/null 2>&1
        mkdir /tmp/docker-se > /dev/null 2>&1
        tar -zxf /tmp/docker-${DOCKER_BINARY_VERSION}-amd64.tgz -C /tmp/docker-se
        /bin/cp -a /tmp/docker-se/docker/* /usr/bin/ > /dev/null 2>&1
    fi

    ##ARM架构
    if [[ "${MACH}" == "aarch64" ]]; then
        if [[ "${check_network_code}" == "000" ]]; then
           if ! file_exists /tmp/docker-${DOCKER_BINARY_VERSION}-arm64.tgz; then
              if ! file_exists "${OFFLINE_DIR}/packages-arm64/docker-${DOCKER_BINARY_VERSION}-arm64.tgz"; then
                 echo "找不到Docker离线安装包, 请检查目录temp_files/packages-arm64下是否存在docker-${DOCKER_BINARY_VERSION}-arm64.tgz"|tee -a ${platform_err_log}
                 echo "如果缺失docker-${DOCKER_BINARY_VERSION}-arm64.tgz文件, 请按照官方文档重新下载离线包进行安装"|tee -a ${platform_err_log}
                 exit 1;
              else
                 echo "install docker from local package - waiting for it ..."
                 /bin/cp -ra "${OFFLINE_DIR}/packages-arm64/docker-${DOCKER_BINARY_VERSION}-arm64.tgz" /tmp/
              fi
           fi
           if ! file_exists /usr/bin/docker-compose; then
              if ! file_exists "${OFFLINE_DIR}/packages-arm64/docker-compose"; then
                 echo "找不到Docker-compose离线安装包, 请检查目录temp_files/packages-arm64是否存在docker-compose"|tee -a ${platform_err_log}
                 echo "如果缺失Docker-compose文件, 请按照官方文档重新下载离线包进行安装"|tee -a ${platform_err_log}
                 exit 1;
              else
                 /bin/cp -ra "${OFFLINE_DIR}/packages-arm64/docker-compose" /usr/bin/
                 chmod +x /usr/bin/docker-compose
              fi
           fi
        fi
        if [[ "${check_network_code}" == "200" ]]; then
           if ! file_exists /tmp/docker-${DOCKER_BINARY_VERSION}-arm64.tgz; then
              echo -e "\ninstall docker from internet package - waiting for it ..."|tee -a ${platform_msg_log}
              download_file_retry "${DOCKER_BINARY_ARM64}" "/tmp/docker-${DOCKER_BINARY_VERSION}-arm64.tgz" "Docker安装包"
              if [ $? -eq 0 ]; then
                 echo "下载docker安装包成功" >> ${platform_msg_log} 2>&1
              else
                 echo "下载docker安装包失败, 安装中断, 请确保网络连通正常再重新安装"|tee -a ${platform_err_log}
                 exit 1;
              fi
           fi
        fi

        /bin/rm -rf /tmp/docker-se > /dev/null 2>&1
        mkdir /tmp/docker-se > /dev/null 2>&1
        tar -zxf /tmp/docker-${DOCKER_BINARY_VERSION}-arm64.tgz -C /tmp/docker-se
        /bin/cp -a /tmp/docker-se/docker/* /usr/bin/ > /dev/null 2>&1
    fi
}

install_docker_using_script () {
    echo "install docker - waiting for it ..."|tee -a ${platform_err_log}
    curl -fsSL https://get.docker.com -o get-docker.sh
    /bin/bash get-docker.sh
    /bin/rm get-docker.sh
}

config_docker0_bridge () {
    ##新安装docker时配置docker0网桥网段, 避免使用默认的172.17.0.0/16网段
    ##docker0使用10.200.201.0/24网段, 自定义网络默认从10.200.200.0/24分配
    ##不依赖jq命令, 使用sed实现, 适配离线环境
    local DOCKER_CONF_DIR="/etc/docker"
    local DOCKER_DAEMON_JSON="${DOCKER_CONF_DIR}/daemon.json"
    local DOCKER0_BIP="10.200.201.1/24"

    mkdir -p ${DOCKER_CONF_DIR} > /dev/null 2>&1

    if [[ -f ${DOCKER_DAEMON_JSON} ]]; then
        ##daemon.json已存在, 检查是否已配置bip
        if grep -q '"bip"' ${DOCKER_DAEMON_JSON} 2>/dev/null; then
            echo -e "\ndaemon.json已配置bip, 跳过docker0网段配置" >> ${platform_msg_log} 2>&1
        else
            ##备份后用sed插入bip字段, 不依赖jq
            /bin/cp -f ${DOCKER_DAEMON_JSON} ${DOCKER_DAEMON_JSON}.bak_$(date +%Y%m%d_%H%M%S)
            ##检查是否已有其他配置项(排除空JSON {})
            if grep -qE '"[a-zA-Z_-]+"\s*:' ${DOCKER_DAEMON_JSON} 2>/dev/null; then
                ##已有配置项: 用sed在第一个{后插入bip, 使用|作为分隔符避免IP中/冲突
                sed -i '0,/{/s|{|{\n  "bip": "'"${DOCKER0_BIP}"'",|' ${DOCKER_DAEMON_JSON}
            else
                ##空JSON {}: 直接写入完整配置
                cat > ${DOCKER_DAEMON_JSON} << EOF
{
  "bip": "${DOCKER0_BIP}",
  "default-address-pools": [
    {"base": "10.200.200.0/24", "size": 24}
  ]
}
EOF
            fi
            echo -e "\n已为docker0网桥配置网段: ${DOCKER0_BIP}(原配置已备份)" | tee -a ${platform_msg_log}
        fi
    else
        cat > ${DOCKER_DAEMON_JSON} << EOF
{
  "bip": "${DOCKER0_BIP}",
  "default-address-pools": [
    {"base": "10.200.200.0/24", "size": 24}
  ]
}
EOF
        echo -e "\n已为docker0网桥配置网段: ${DOCKER0_BIP}" | tee -a ${platform_msg_log}
    fi
}

install_docker_using_binary () {
get_docker_binary_files
if ! file_exists /usr/lib/systemd/system/docker.service;then
cat > /usr/lib/systemd/system/docker.service << EOF
[Unit]
Description=Docker Application Container Engine
Documentation=https://docs.docker.com
After=network-online.target firewalld.service
Wants=network-online.target
[Service]
Type=notify
ExecStart=/usr/bin/dockerd
ExecReload=/bin/kill -s HUP $MAINPID
LimitCORE=65535
LimitNOFILE=65535
LimitNPROC=65535
TimeoutStartSec=0
Delegate=yes
KillMode=process
Restart=on-failure
StartLimitBurst=3
StartLimitInterval=60s
[Install]
WantedBy=multi-user.target
EOF
fi
systemctl daemon-reload
##新安装docker时配置docker0网桥网段, 避免使用默认的172.17.0.0/16网段
config_docker0_bridge
}

install_docker_service () {
    if [[ "${REV}" == "OpenCloudOS" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == "Tencent Linux" ]]; then   #TencentOS 2.4
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == TencentOS* ]]; then        #TencentOS 3.1
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == "openEuler" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == "Huawei Cloud EulerOS" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == "EulerOS" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
        sed -i 's/umask 0077/umask 0022/g' /etc/bashrc
        source /etc/bashrc
    elif [[ "${DIST}" == CentOS* ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == Red* ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == "Ubuntu" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == "Rocky Linux" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == "Debian" ]] || [[ "${DIST}" == "Fedora" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
     elif [[ "${DIST}" == "uos" ]] || [[ "${DIST}" == "kylin" ]] || [[ "${DIST}" == "UOS Server" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
     elif [[ "${DIST}" == "opensuse-leap" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
     elif [[ "${DIST}" == "NFS" ]]; then
        install_docker_using_binary
        systemctl start docker
        systemctl enable docker
    elif [[ "${DIST}" == "SuSe" ]]; then
        echo "Your operating system does not allow Docker CE installation."
        echo "You can install Docker EE using the manual here - https://docs.docker.com/engine/installation/linux/suse/"
        exit 1;
    else
        echo "Docker could not be installed automatically."
        echo "Please use this official instruction https://docs.docker.com/engine/installation/linux/other/ for its manual installation."
        exit 1;
    fi
    if ! command_exists docker ; then
        echo "安装docker服务失败,请查看系统日志获取失败原因"|tee -a ${platform_err_log}
        echo "Linux系统日志通常为/var/log/messages或/var/log/syslog"|tee -a ${platform_err_log}
        exit 1;
    fi

    echo -e "\n记录docker版本信息: $(docker --version)" >> ${platform_msg_log} 2>&1
    echo -e "\n记录docker版本信息: $(docker --version)" >> ${platform_err_log} 2>&1
}

# 配置 docker images 显示格式
config_docker_images_format () {
    local docker_config_dir="$HOME/.docker"
    local docker_config_file="${docker_config_dir}/config.json"
    local images_format_value="table {{.Repository}}\t{{.Tag}}\t{{.ID}}\t{{.CreatedAt}}\t{{.Size}}"

    if [[ ! -d "${docker_config_dir}" ]]; then
        mkdir -p "${docker_config_dir}"
    fi

    if [[ -f "${docker_config_file}" ]]; then
        # 已有配置文件, 合并 imagesFormat 字段
        local tmp_file="${docker_config_dir}/config.json.tmp"
        if command_exists jq ; then
            jq --arg fmt "${images_format_value}" '. + {"imagesFormat": $fmt}' "${docker_config_file}" > "${tmp_file}" && mv "${tmp_file}" "${docker_config_file}"
        else
            # 无 jq 时用 sed 在文件最后一个 } 前插入字段
            # 先检查是否已有 imagesFormat 字段
            if grep -q '"imagesFormat"' "${docker_config_file}" 2>/dev/null; then
                sed -i 's/"imagesFormat"[[:space:]]*:[[:space:]]*"[^"]*"/"imagesFormat": "'${images_format_value}'"/' "${docker_config_file}"
            else
                # 在最后一个 } 前插入新字段
                sed -i 's/}$/,\n  "imagesFormat": "'${images_format_value}'"\n}/' "${docker_config_file}"
            fi
        fi
    else
        # 无配置文件, 创建新文件
        printf '{\n  "imagesFormat": "%s"\n}\n' "${images_format_value}" > "${docker_config_file}"
    fi

    echo "配置docker images显示格式完成" >> ${platform_msg_log} 2>&1
}

install_docker () {
    if command_exists docker ; then
        check_docker
        start_docker
    else
        install_docker_service
    fi
    # 配置 docker images 显示格式
    config_docker_images_format
}

check_docker_status () {
    echo "check docker health report" >> ${platform_msg_log} 2>&1
    docker ps 2>/dev/null | grep 'CONTAINER ID' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       echo -e "\n\033[1;31m
       Docker进程状态检测失败, 请查看系统日志获取失败原因;
       Linux系统日志通常为/var/log/messages或/var/log/syslog;
       如无法确切定位启动失败原因, 请从以下几方面分析:
           1.服务器存储驱动问题;
           2.服务器内核版本太低或缺少必须模块(overlay和br_netfilter);
           3.SELinux/AppArmor安全策略限制;
           4.docker配置文件错误(如无手动修改过则忽略);

       如无法定位问题原因, 请尝试重启服务器后再重试安装;
       如果重启后依然安装失败, 建议更换官网部署页面中推荐的操作系统重新部署.
       \033[0m"|tee -a ${platform_err_log}
       exit 1
    else
       echo -e "Docker进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

import_images () {
    docker_list=$(docker images|grep -E '/workplus|/workapps|/workdbs'|wc -l)
    if [[ "${docker_list}" -lt "19" ]]; then
       echo "检测到本地不存在完整镜像列表, 根据服务器联网状态获取所需镜像资源" >> ${platform_msg_log} 2>&1
       if [[ "${check_network_code}" == "000" ]]; then
          if [[ "${MACH}" == "x86_64" ]]; then
              if ! file_exists "${OFFLINE_DIR}/packages-amd64/images-${WP_VERSION}-amd64.tar.gz"; then
                 echo "检测到服务器无法连接互联网, 需要从本地导入离线镜像资源"|tee -a ${platform_err_log}
                 echo "找不到镜像离线包, 请检查temp_files/packages-amd64目录下是否存在images-${WP_VERSION}-amd64.tar.gz"|tee -a ${platform_err_log}
                 exit 1;
              else
                 echo "import docker images files - waiting for it ..."|tee -a ${platform_msg_log}
                 echo -e "\033[1;05m正在导入镜像资源, 受系统性能影响, 最长可能需要十几分钟, 请稍后\033[0m"
                 docker load < "${OFFLINE_DIR}/packages-amd64/images-${WP_VERSION}-amd64.tar.gz"
              fi
          fi
          if [[ "${MACH}" == "aarch64" ]]; then
              if ! file_exists "${OFFLINE_DIR}/packages-arm64/images-${WP_VERSION}.tar.gz"; then
                 echo "检测到服务器无法连接互联网, 需要从本地导入离线镜像资源"|tee -a ${platform_err_log}
                 echo "找不到镜像离线包, 请检查temp_files/packages-arm64目录下是否存在images-${WP_VERSION}.tar.gz"|tee -a ${platform_err_log}
                 exit 1;
              else
                 echo "import docker images files - waiting for it ..."|tee -a ${platform_msg_log}
                 echo -e "\033[1;05m正在导入镜像资源, 受系统性能影响, 最长可能需要十几分钟, 请稍后\033[0m"
                 docker load < "${OFFLINE_DIR}/packages-arm64/images-${WP_VERSION}.tar.gz"
              fi
          fi

       else
          echo "服务器可访问互联网, 跳过全量导入离线包步骤" >> ${platform_msg_log} 2>&1
       fi
    else
       echo "服务器已存在镜像列表, 跳过全量导入离线包步骤" >> ${platform_msg_log} 2>&1
    fi
}

check_mysql_status () {
    echo -e "\ncheck mysql health report" >> ${platform_msg_log} 2>&1
    docker exec $MYSQL_CONTAINER_NAME sh -c 'exec mysqladmin --version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       echo "MySQL进程状态获取失败,请检查日志信息"|tee -a ${platform_err_log}
       docker logs -n 20 $MYSQL_CONTAINER_NAME|tee -a ${platform_err_log}
    else
       echo "MYSQL进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

check_mysql_alive () {
    counter=0
    max_attempts=120
    check_interval=5
    echo "开始检测MySQL服务可用性(最多检测 ${max_attempts} 次，每次间隔 ${check_interval} 秒)" >> ${platform_msg_log} 2>&1

#    until docker exec ${MYSQL_SERVER_ID} sh -c 'exec mysqladmin ping -P 3306 -uroot -p"$MYSQL_ROOT_PASSWORD"' | grep "mysqld is alive" ; do
#    >&2 echo "mysqld is unavailable - waiting for it ..."
#    sleep 5
#    counter=$((counter + 1))
#    if [ $counter -ge $max_attempts ]; then
#       >&2 echo "Error: MySQL did not become available after $max_attempts attempts"|tee -a ${platform_err_log}
#       exit 1
#    fi
#    done

    until docker exec ${MYSQL_SERVER_ID} sh -c 'exec mysqladmin ping -P 3306 -uroot -p"$MYSQL_ROOT_PASSWORD"' 2>/dev/null | grep -q "mysqld is alive" ;
    do
      counter=$((counter + 1))
      >&2 echo "[尝试 ${counter}/${max_attempts}] MySQL服务尚未启动完成, 等待中..."
      sleep ${check_interval}

      if [ ${counter} -ge ${max_attempts} ]; then
         echo "启动异常: 经过 ${max_attempts} 次检测后MySQL服务仍然不可用" | tee -a ${platform_err_log}
         echo "可能的原因:" | tee -a ${platform_err_log}
         echo "1. MySQL容器未正常启动" | tee -a ${platform_err_log}
         echo "2. MySQL服务启动过程中出现错误" | tee -a ${platform_err_log}
         echo "3. 默认root用户未完成初始化" | tee -a ${platform_err_log}
         echo "4. 网络连接问题,无法访问容器服务内部端口" | tee -a ${platform_err_log}
         echo "5. 服务器性能较低,导致服务启动超时,请检查系统负载和内存使用率" | tee -a ${platform_err_log}
         echo "" | tee -a ${platform_err_log}
         echo "建议的排查步骤:" | tee -a ${platform_err_log}
         echo "1. 检查服务器负载: top -n 1|head -n 5" | tee -a ${platform_err_log}
         echo "2. 检查服务器内存: free -g" | tee -a ${platform_err_log}
         echo "3. 检查容器启动状态: docker ps -a | grep ${MYSQL_CONTAINER_NAME}" | tee -a ${platform_err_log}
         echo "4. 查看容器运行日志: docker logs -n 100 ${MYSQL_CONTAINER_NAME}" | tee -a ${platform_err_log}
         echo '5. 检查容器内部状态: docker exec -t db-mysql sh -c '\''exec mysqladmin status -P 3306 -uroot -p"${MYSQL_ROOT_PASSWORD}"'\'| tee -a ${platform_err_log}
         echo "" | tee -a ${platform_err_log}
         echo "日志关键信息：" | tee -a ${platform_err_log}
         echo "查看容器运行日志，如果出现'MySQL init process done. Ready for start up'，说明MySQL服务已经启动成功，没有则说明尚未启动完成" | tee -a ${platform_err_log}
         echo "" | tee -a ${platform_err_log}
         echo "如无法定位问题原因, 请尝试重启服务器后再重试安装;" | tee -a ${platform_err_log}
         echo "如果重启后依然安装失败, 建议更换官网部署页面中推荐的操作系统重新部署" | tee -a ${platform_err_log}
         exit 1
      fi
    done
    echo "MYSQL is already alive."|tee -a ${platform_msg_log}
}

repair_mysql_table () {
    echo -e "\n重新下载mysql数据库表结构文件修复表数量异常问题"|tee -a ${platform_err_log}
    curl -o ${WP_DIR}/mysql/temp/workplus-${DB_VERSION}-SE.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/workplus-${DB_VERSION}-SE.sql >> ${platform_err_log} 2>&1
    [ $? -eq 0 ] && echo -e "重新下载mysql数据库表结构文件1成功" >> ${platform_msg_log} || { echo "下载数据库表结构文件1超时失败,请确保网络连通正常,可再次尝试安装"|tee -a ${platform_err_log} && exit 1; }
    curl -o ${WP_DIR}/mysql/temp/calendar-${DB_VERSION}-SE.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/calendar-${DB_VERSION}-SE.sql >> ${platform_err_log} 2>&1
    [ $? -eq 0 ] && echo -e "重新下载mysql数据库表结构文件2成功" >> ${platform_msg_log} || { echo "下载数据库表结构文件2超时失败,请确保网络连通正常,可再次尝试安装"|tee -a ${platform_err_log} && exit 1; }
    curl -o ${WP_DIR}/mysql/temp/auditlog-${DB_VERSION}-SE.sql http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/auditlog-${DB_VERSION}-SE.sql >> ${platform_err_log} 2>&1
    [ $? -eq 0 ] && echo -e "重新下载mysql数据库表结构文件3成功" >> ${platform_msg_log} || { echo "下载数据库表结构文件3超时失败,请确保网络连通正常,可再次尝试安装"|tee -a ${platform_err_log} && exit 1; }

    docker cp ${WP_DIR}/mysql/temp/workplus-${DB_VERSION}-SE.sql ${MYSQL_CONTAINER_NAME}:/tmp/ >> ${platform_err_log} 2>&1;
    docker cp ${WP_DIR}/mysql/temp/calendar-${DB_VERSION}-SE.sql ${MYSQL_CONTAINER_NAME}:/tmp/ >> ${platform_err_log} 2>&1;
    docker cp ${WP_DIR}/mysql/temp/auditlog-${DB_VERSION}-SE.sql ${MYSQL_CONTAINER_NAME}:/tmp/ >> ${platform_err_log} 2>&1;

    echo -e "\n重新导入mysql数据库表结构文件修复表数量异常问题"|tee -a ${platform_err_log}
    docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/workplus-${DB_VERSION}-SE.sql;"' >> ${platform_err_log} 2>&1;
    docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/calendar-${DB_VERSION}-SE.sql;"' >> ${platform_err_log} 2>&1;
    docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_auditlog -e "source /tmp/auditlog-${DB_VERSION}-SE.sql;"' >> ${platform_err_log} 2>&1;
}

check_mysql_table () {
    if [[ "${DB_DRIVER}" != "mysql" ]]; then
       return
    fi
    echo -e "\ncheck mysql table numbers" >> ${platform_msg_log} 2>&1
    tbnum=$(docker exec ${MYSQL_CONTAINER_NAME} sh -c "exec mysql --silent --raw -u\"${MYSQL_USER}\" -p\"${MYSQL_PASS}\" -e \"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${MYSQL_DATABASE}';\"")

    if ! [[ "$tbnum" =~ ^[0-9]+$ ]]; then
        echo "错误: 数据库${MYSQL_DATABASE}表数量获取失败, 返回值: $tbnum"|tee -a ${platform_err_log}
        echo "请检查mysql容器状态:"|tee -a ${platform_err_log}
        docker ps -a | grep ${MYSQL_CONTAINER_NAME}|tee -a ${platform_err_log}
        echo "请检查日志信息获取失败原因:"|tee -a ${platform_err_log}
        docker logs -n 50 ${MYSQL_CONTAINER_NAME}|tee -a ${platform_err_log}
    else
        if [ "$tbnum" -lt "400" ]; then
           repair_mysql_table
           tbnum=$(docker exec ${MYSQL_CONTAINER_NAME} sh -c "exec mysql --silent --raw -u\"${MYSQL_USER}\" -p\"${MYSQL_PASS}\" -e \"SELECT COUNT(*) FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = '${MYSQL_DATABASE}';\"")
           echo "数据库${MYSQL_DATABASE}中的表数量: $tbnum"|tee -a ${platform_msg_log}
           if [ "$tbnum" -lt "400" ]; then
              echo -e "$(date '+%Y-%m-%d %H:%M:%S') 开始记录最近100条日志到错误日志文件" >> ${platform_err_log} 2>&1
              docker logs -n 100 ${MYSQL_CONTAINER_NAME} >> ${platform_err_log} 2>&1
              echo -e "\033[1;31m
              警告: 数据库${MYSQL_DATABASE}表数量异常(当前:${tbnum}), 完整表数量不少于400。

              建议的排查步骤:
              1.查看日志文件是否记录到异常信息, 日志文件:${platform_err_log}
              2.检查容器启动状态: docker ps -a | grep ${MYSQL_CONTAINER_NAME}

              异常的可能原因:
              1.网络连接不稳定,下载的数据库表结构文件不完整
              2.服务器运行不稳定,数据库导入表结构过程发生异常

              建议的解决方案:
              如无法定位问题原因, 请卸载mysql服务后再尝试安装;
              docker stop ${MYSQL_CONTAINER_NAME};
              docker rm ${MYSQL_CONTAINER_NAME};
              docker rmi $(docker images|grep 'workdbs/mysql'|awk '{print $3}');
              rm -rf ${WP_DIR}/mysql;
              \033[0m"|tee -a ${platform_err_log}
              exit 1
           fi
        else
           echo "数据库${MYSQL_DATABASE}中的表数量: $tbnum" >> ${platform_msg_log} 2>&1
        fi
    fi
}

install_mysql () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    if [[ "${DB_DRIVER}" != "mysql" ]]; then
       return
    fi
    download_image "$MYSQL_IMAGE_NAME:$MYSQL_IMAGE_TAG" "$MYSQL_CONTAINER_NAME"
    MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
    RUN_MYSQL_SERVER="true";
    if [[ -n ${MYSQL_SERVER_ID} ]]; then
        RUN_MYSQL_SERVER="false";
        echo "MYSQL is already installed."|tee -a ${platform_msg_log}
        docker start ${MYSQL_SERVER_ID} >> /dev/null;
        sleep 15
        check_mysql_alive
    fi

    if [[ "$RUN_MYSQL_SERVER" == "true" ]]; then
        args=();
        args+=(--name "$MYSQL_CONTAINER_NAME");
#       args+=(-p 3307:3306);
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-v "${WP_DIR}/mysql/data:/var/lib/mysql");
#       args+=(-v "${WP_DIR}/mysql/logs:/var/log");
        args+=(-v "${WP_DIR}/mysql/initdb.d:/docker-entrypoint-initdb.d");
        args+=(-e "MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD");
        args+=(-e "MYSQL_DATABASE=$MYSQL_DATABASE");
        args+=(-e "MYSQL_USER=$MYSQL_USER");
        args+=(-e "MYSQL_PASSWORD=$MYSQL_PASS");
        args+=("$MYSQL_IMAGE_NAME:$MYSQL_IMAGE_TAG");  #镜像前配置的是容器参数,镜像后配置的是mysql运行参数
        args+=("--skip_host_cache");
        args+=("--skip_name_resolve");
        args+=("--max_connections=5000");
        args+=("--max_connect_errors=100000");
        args+=("--max_allowed_packet=32M");
        args+=("--table_open_cache=4096");
        args+=("--tmp_table_size=512M");
        args+=("--max_heap_table_size=512M");
        args+=("--max_allowed_packet=200M");
        args+=("--sort_buffer_size=32M");
        args+=("--join_buffer_size=32M");
        args+=("--thread_cache_size=64");
        args+=("--character-set-server=utf8mb4");
        args+=("--collation-server=utf8mb4_unicode_ci");
        args+=("--default-authentication-plugin=mysql_native_password");
        args+=("--lower_case_table_names=1");
#       args+=("--mysql_native_password=ON");
        args+=("--sql_mode=");
        args+=("--innodb_buffer_pool_size=4G");
        args+=("--innodb_log_file_size=1024M");
        args+=("--innodb_log_buffer_size=1024M");
        args+=("--innodb_log_files_in_group=3");
        args+=("--innodb_thread_concurrency=0");
        args+=("--innodb_write_io_threads=8");
        args+=("--innodb_read_io_threads=8");
        args+=("--gtid_mode=ON");
        args+=("--enforce_gtid_consistency=ON");
        args+=("--master_info_repository=TABLE");
        args+=("--relay_log_info_repository=TABLE");
        args+=("--relay-log=localhost-relay-bin");
        args+=("--slow_query_log=1");
        args+=("--long_query_time=2");
#       args+=("--log-error=/dev/stderr");
        args+=("--log-error=/var/lib/mysql/mysqld.log");
        args+=("--slow-query-log-file=/var/lib/mysql/mysql-slow.log");

        ##部分旧架构CPU不支持mysql-8,需要安装mysql-5,但5系列不支持以下三个参数
        if [[ ${MYSQL_IMAGE_TAG} == 8* ]]; then
        args+=("--replica_parallel_type=LOGICAL_CLOCK");
        args+=("--replica_parallel_workers=4");
        args+=("--replica_preserve_commit_order=1");
        fi
        echo "create mysql container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        if [ $? -eq 0 ]; then
           echo "create mysql container success"|tee -a ${platform_msg_log}
        else
           echo "create mysql container failed"|tee -a ${platform_err_log}
        fi

        MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
        if [[ -z ${MYSQL_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: MYSQL not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep ${MYSQL_CONTAINER_NAME}
            2.检查容器启动日志: docker logs -n 100 ${MYSQL_CONTAINER_NAME}

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop ${MYSQL_CONTAINER_NAME};
            docker rm ${MYSQL_CONTAINER_NAME};
            docker rmi $(docker images|grep 'workdbs/mysql'|awk '{print $3}');
            rm -rf ${WP_DIR}/mysql;
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        echo "mysql is starting up - waiting for it ..."|tee -a ${platform_msg_log}
        sleep_time 60
        check_mysql_alive

#       counter=0
#       max_attempts=20
#       until docker exec ${MYSQL_SERVER_ID} sh -c 'exec mysqladmin ping -P 3306 -uroot -p"$MYSQL_ROOT_PASSWORD"' | grep "mysqld is alive" ; do
#       >&2 echo "mysqld is unavailable - waiting for it ..."
#       sleep 2
#       counter=$((counter + 1))
#       if [ $counter -ge $max_attempts ]; then
#          >&2 echo "Error: MySQL did not become available after $max_attempts attempts"|tee -a ${platform_err_log}
#          exit 1
#       fi
#       done

        mysql_db_count=$(docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "show databases;"' 2>/dev/null | grep -wE "${MYSQL_DATABASE}|wp_auditlog|wp_services_jobs|wp_calendar_jobs|wp_auditlog_jobs"|wc -l)
        if [[ "${mysql_db_count}" -ge 2 ]]; then
           echo "The database has been initialized, skip initialization"|tee -a ${platform_msg_log};
           return 0
        fi

        echo "create quartz databases - waiting for it ..."|tee -a ${platform_msg_log}
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "create database wp_services_jobs;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "create database wp_calendar_jobs;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "create database wp_auditlog_jobs;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" -e "create database wp_auditlog;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" -e \"GRANT ALL PRIVILEGES ON *.* TO 'workplus'@'%';\"" >> ${platform_msg_log} 2>&1;
        docker cp ${WP_DIR}/mysql/temp/workplus_jobs.sql ${MYSQL_CONTAINER_NAME}:/tmp/ >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services_jobs -e "source /tmp/workplus_jobs.sql;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_calendar_jobs -e "source /tmp/workplus_jobs.sql;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_auditlog_jobs -e "source /tmp/workplus_jobs.sql;"' >> ${platform_msg_log} 2>&1;
        echo "create server databases - waiting for it ..."|tee -a ${platform_msg_log}
        docker cp ${WP_DIR}/mysql/temp/workplus-${DB_VERSION}-SE.sql ${MYSQL_CONTAINER_NAME}:/tmp/workplus-se.sql >> ${platform_msg_log} 2>&1;
        docker cp ${WP_DIR}/mysql/temp/calendar-${DB_VERSION}-SE.sql ${MYSQL_CONTAINER_NAME}:/tmp/calendar-se.sql >> ${platform_msg_log} 2>&1;
        docker cp ${WP_DIR}/mysql/temp/auditlog-${DB_VERSION}-SE.sql ${MYSQL_CONTAINER_NAME}:/tmp/auditlog-se.sql >> ${platform_msg_log} 2>&1;
        docker cp ${WP_DIR}/mysql/temp/workplus_bpm.sql ${MYSQL_CONTAINER_NAME}:/tmp/workplus_bpm.sql >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/workplus-se.sql;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/calendar-se.sql;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_auditlog -e "source /tmp/auditlog-se.sql;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/workplus_bpm.sql;"' >> ${platform_msg_log} 2>&1;
    fi
}

check_mongo_status () {
    echo "check mongo health report" >> ${platform_msg_log} 2>&1
    docker exec $MONGO_CONTAINER_NAME sh -c 'exec mongod --version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 30 $MONGO_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       Mongo进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $MONGO_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $MONGO_CONTAINER_NAME;
       docker rm $MONGO_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workdbs/mongo'|awk '{print $3}');
       rm -rf ${WP_DIR}/mongo;
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Mongo进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_mongo () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$MONGO_IMAGE_NAME:$MONGO_IMAGE_TAG" "$MONGO_CONTAINER_NAME"
    MONGO_SERVER_ID=$(get_container_id "$MONGO_CONTAINER_NAME");
    RUN_MONGO_SERVER="true";
    if [[ -n ${MONGO_SERVER_ID} ]]; then
        RUN_MONGO_SERVER="false";
        echo "MONGO is already installed."
        docker start ${MONGO_SERVER_ID} >> /dev/null;
        sleep 10
        check_mongo_status
    fi

    if [[ "$RUN_MONGO_SERVER" == "true" ]]; then
        args=();
        args+=(--name "$MONGO_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-v "${WP_DIR}/mongo/data:/data/db");
        args+=(-v "${WP_DIR}/mongo/initdb.d:/docker-entrypoint-initdb.d");
        args+=(-e "MONGO_INITDB_ROOT_USERNAME=$MONGO_USER");
        args+=(-e "MONGO_INITDB_ROOT_PASSWORD=$MONGO_PASS");
        args+=(-e "MONGO_INITDB_DATABASE=$MONGO_DATABASE");
        args+=("$MONGO_IMAGE_NAME:$MONGO_IMAGE_TAG");

        echo "create mongodb container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}" --wiredTigerCacheSizeGB 5 --bind_ip_all|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create mongodb container success"|tee -a ${platform_msg_log} || echo "create mongodb container failed"|tee -a $platform_err_log

        MONGO_SERVER_ID=$(get_container_id "$MONGO_CONTAINER_NAME");
        if [[ -z ${MONGO_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: MONGO not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $MONGO_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $MONGO_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $MONGO_CONTAINER_NAME;
            docker rm $MONGO_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workdbs/mongo'|awk '{print $3}');
            rm -rf ${WP_DIR}/mongo;
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_mongo_status
    fi
}

check_redis_status () {
    echo "check redis health report" >> ${platform_msg_log} 2>&1
    docker exec $REDIS_CONTAINER_NAME sh -c 'exec redis-cli --version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 30 $REDIS_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       Redis进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $REDIS_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $REDIS_CONTAINER_NAME;
       docker rm $REDIS_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workdbs/redis'|awk '{print $3}');
       rm -rf ${WP_DIR}/redis;
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Redis进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_redis () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$REDIS_IMAGE_NAME:$REDIS_IMAGE_TAG" "$REDIS_CONTAINER_NAME"
    REDIS_SERVER_ID=$(get_container_id "$REDIS_CONTAINER_NAME");
    RUN_REDIS_SERVER="true";
    if [[ -n ${REDIS_SERVER_ID} ]]; then
        RUN_REDIS_SERVER="false";
        echo "REDIS is already installed."
        docker start ${REDIS_SERVER_ID} >> /dev/null;
        sleep 10
        check_redis_status
    fi

    if [[ "$RUN_REDIS_SERVER" == "true" ]]; then

        args=();
        args+=(--name "$REDIS_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-v "${WP_DIR}/redis/data:/data");
        args+=("$REDIS_IMAGE_NAME:$REDIS_IMAGE_TAG");

        echo "create redis container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
#       docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}" --requirepass "workplus" >> /dev/null;
        [ $? -eq 0 ] && echo "create redis container success"|tee -a ${platform_msg_log} || echo "create redis container failed"|tee -a $platform_err_log

        REDIS_SERVER_ID=$(get_container_id "$REDIS_CONTAINER_NAME");
        if [[ -z ${REDIS_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: REDIS not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $REDIS_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $REDIS_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $REDIS_CONTAINER_NAME;
            docker rm $REDIS_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workdbs/redis'|awk '{print $3}');
            rm -rf ${WP_DIR}/redis;
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_redis_status
    fi
}

install_fastdfs () {
    FASTDFS_SERVER_ID=$(get_container_id "$FASTDFS_CONTAINER_NAME");
    RUN_FASTDFS_SERVER="true";
    if [[ -n ${FASTDFS_SERVER_ID} ]]; then
        RUN_FASTDFS_SERVER="false";
        echo "FASTDFS is already installed."
        docker start ${FASTDFS_SERVER_ID} >> /dev/null;
    fi

    if [[ "$RUN_FASTDFS_SERVER" == "true" ]]; then
        args=();
        args+=(--name "$FASTDFS_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-v "${WP_DIR}/fdfs:/fdfs");
        args+=("$FASTDFS_IMAGE_NAME:$FASTDFS_IMAGE_TAG");

        echo "create fastdfs container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create fastdfs container success"|tee -a ${platform_msg_log} || echo "create fastdfs container failed"|tee -a $platform_err_log

        FASTDFS_SERVER_ID=$(get_container_id "$FASTDFS_CONTAINER_NAME");
        if [[ -z ${FASTDFS_SERVER_ID} ]]; then
           echo "FASTDFS not installed."|tee -a ${platform_err_log}
           exit 1;
        fi
    fi
}

get_minio_info () {
    if file_exists ${HOME}/.minioinfo; then
      source ${HOME}/.minioinfo;
    else
      echo -e "MINIO_ROOT_USER=miniouser\nMINIO_ROOT_PASSWORD=minio098456\nMINIO_API_PORT=9876\nMINIO_WEB_PORT=9877" > ${HOME}/.minioinfo;
      echo -e "\n#旧版默认信息\n#MINIO_ROOT_USER=minioadmin\n#MINIO_ROOT_PASSWORD=minioadmin\n#MINIO_API_PORT=9000\n#MINIO_WEB_PORT=9001" >> ${HOME}/.minioinfo;
      source ${HOME}/.minioinfo;
    fi
}

check_minio_status () {
    echo "check minio health report" >> ${platform_msg_log} 2>&1
    docker exec $MINIO_CONTAINER_NAME sh -c 'exec minio --version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 30 $MINIO_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       Minio进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $MINIO_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $MINIO_CONTAINER_NAME;
       docker rm $MINIO_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workdbs/minio'|awk '{print $3}');
       rm -rf ${WP_DIR}/minio;
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Minio进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_minio () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    get_minio_info
    download_image "$MINIO_IMAGE_NAME:$MINIO_IMAGE_TAG" "$MINIO_CONTAINER_NAME"
    MINIO_SERVER_ID=$(get_container_id "$MINIO_CONTAINER_NAME");
    RUN_MINIO_SERVER="true";
    if [[ -n ${MINIO_SERVER_ID} ]]; then
        RUN_MINIO_SERVER="false";
        echo "MINIO is already installed."
        docker start ${MINIO_SERVER_ID} >> /dev/null;
        sleep 10
        check_minio_status
    fi

    if [[ "$RUN_MINIO_SERVER" == "true" ]]; then
        args=();
        args+=(--name "$MINIO_CONTAINER_NAME");
#       args+=(-p ${MINIO_API_PORT}:${MINIO_API_PORT} -p ${MINIO_WEB_PORT}:${MINIO_WEB_PORT});
        args+=(-e "MINIO_ROOT_USER=$MINIO_ROOT_USER");
        args+=(-e "MINIO_ROOT_PASSWORD=$MINIO_ROOT_PASSWORD");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-v "${WP_DIR}/minio:/data");
        args+=("$MINIO_IMAGE_NAME:$MINIO_IMAGE_TAG" server /data --address ":${MINIO_API_PORT}" --console-address ":${MINIO_WEB_PORT}");

        echo "create minio container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create minio container success"|tee -a ${platform_msg_log} || echo "create minio container failed"|tee -a $platform_err_log

        MINIO_SERVER_ID=$(get_container_id "$MINIO_CONTAINER_NAME");
        if [[ -z ${MINIO_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: MINIO not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $MINIO_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $MINIO_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $MINIO_CONTAINER_NAME;
            docker rm $MINIO_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workdbs/minio'|awk '{print $3}');
            rm -rf ${WP_DIR}/minio;
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_minio_status
    fi
}

update_wphost () {
     if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]]; then
        echo "update visit host - waiting for it ..."|tee -a ${platform_msg_log}
        echo "update visit host - stop related services ..."|tee -a ${platform_msg_log}
        docker stop $WP_SERVER_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $WP_SERVER_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $WP_HTTP_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $WP_HTTP_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $WP_DASH_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $WP_DASH_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_BPM_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_BPM_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_FORM_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_FORM_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_TSQ_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_TSQ_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_KAOQIN_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_KAOQIN_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_HTML_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_HTML_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $NGINX_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $NGINX_CONTAINER_NAME > /dev/null 2>&1;
        /bin/mv ${WP_DIR}/nginx/default.conf /tmp/default.conf-$(date +%Y%m%d-%H%M%S) > /dev/null 2>&1;

        echo "确认替换的新地址:" >> ${platform_msg_log}
        echo "${URL_PREFIX}://${WP_HOST}" >> ${platform_msg_log}

        echo "update visit host - reset mysql related data ..."|tee -a ${platform_msg_log}
        ##更新流程大师数据库
        docker exec ${MYSQL_CONTAINER_NAME} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" wp_services -e \"UPDATE act_id_tenant SET PROJECT_BASE_URL_ = '${URL_PREFIX}://${WP_HOST}:9912';\"" 2>> ${platform_err_log};
        ##更新域后台dash路径
        docker exec ${MYSQL_CONTAINER_NAME} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" wp_services -e \"UPDATE domain_settings SET dash_settings = JSON_SET(dash_settings, '$.baseUrl', '${URL_PREFIX}://${WP_HOST}:9910') WHERE dash_settings->>'$.baseUrl' LIKE '%:9910';\"" 2>> ${platform_err_log};
        ##更新域后台http路径
        docker exec ${MYSQL_CONTAINER_NAME} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" wp_services -e \"UPDATE domain_settings SET http_settings = JSON_SET(http_settings, '$.baseUrl', '${URL_PREFIX}://${WP_HOST}:9911') WHERE http_settings->>'$.baseUrl' LIKE '%:9911';\"" 2>> ${platform_err_log};
        ##更新域后台预置应用路径
        docker exec ${MYSQL_CONTAINER_NAME} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" wp_services -e \"UPDATE domain_settings SET dash_settings = JSON_SET(dash_settings, '$.presetKits.guide.baseUrl', '${URL_PREFIX}://${WP_HOST}:9912', '$.presetKits.bpms.baseUrl', '${URL_PREFIX}://${WP_HOST}:9912', '$.presetKits.attend.baseUrl', '${URL_PREFIX}://${WP_HOST}:9912', '$.presetKits.form.baseUrl', '${URL_PREFIX}://${WP_HOST}:9912', '$.presetKits.meet.baseUrl', '${URL_PREFIX}://${WP_HOST}:9912');\"" 2>> ${platform_err_log};
        ##更新应用入口地址
        docker exec ${MYSQL_CONTAINER_NAME} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" wp_services -e \"UPDATE app_entries SET entry_point = CONCAT('${URL_PREFIX}://${WP_HOST}:9912', SUBSTRING(entry_point, LOCATE('/', entry_point, LOCATE('://', entry_point) + 3))) WHERE entry_point IS NOT NULL AND entry_point != '' AND LOCATE('://', entry_point) > 0;\"" 2>> ${platform_err_log};
        ##更新环境变量地址
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysqldump -uroot -p"$MYSQL_ROOT_PASSWORD" --single-transaction --set-gtid-purged=OFF wp_services domain_settings' > /tmp/domain_settings_$(date +%Y%m%d).sql 2>> ${platform_err_log};
        sed -i -E 's#(\\"value\\":\\")https?://[^:]+:((9912|9920)[^"]*)#\1'"${URL_PREFIX}"'://'"${WP_HOST}"':\2#g' /tmp/domain_settings_$(date +%Y%m%d).sql 2>> ${platform_err_log};
        docker cp /tmp/domain_settings_$(date +%Y%m%d).sql ${MYSQL_CONTAINER_NAME}:/tmp/domain_settings.sql 2>> ${platform_err_log};
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/domain_settings.sql;"' 2>> ${platform_err_log};

        echo "update visit host - reset redis related data ..."|tee -a ${platform_msg_log}
        docker exec ${REDIS_CONTAINER_NAME} redis-cli FLUSHALL 2>> ${platform_err_log};

        echo "update visit host - reset mongo related data ..."|tee -a ${platform_msg_log}
        docker exec ${MONGO_CONTAINER_NAME} mongo -u ${MONGO_USER} -p ${MONGO_PASS} --authenticationDatabase admin form --eval "db.dictionarys.updateMany({}, {\$set: {projectBaseUrl: '${URL_PREFIX}://${WP_HOST}:9912'}});" >> ${platform_msg_log} 2>&1;
     fi
}

reset_domain () {
     if [[ "${reset_domain}" == "true" ]]; then
        echo "reinitialize the platform - waiting for it ..."|tee -a ${platform_msg_log}
        echo "reinitialize the platform - stop related services ..."|tee -a ${platform_msg_log}
        docker stop $WP_SERVER_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $WP_SERVER_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $WP_HTTP_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $WP_HTTP_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $WP_DASH_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $WP_DASH_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $WP_DAPR_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $WP_DAPR_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_BPM_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_BPM_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_FORM_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_FORM_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_TSQ_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_TSQ_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_KAOQIN_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_KAOQIN_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $MEETAPI_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $MEETAPI_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $APP_HTML_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $APP_HTML_CONTAINER_NAME > /dev/null 2>&1;

        docker stop $NGINX_CONTAINER_NAME > /dev/null 2>&1;
        docker rm $NGINX_CONTAINER_NAME > /dev/null 2>&1;
        /bin/mv ${WP_DIR}/nginx/default.conf /tmp/default.conf-$(date +%Y%m%d-%H%M%S) > /dev/null 2>&1;

        echo "reinitialize the platform - reset mysql related data ..."|tee -a ${platform_msg_log}
        docker cp ${WP_DIR}/mysql/temp/workplus-${DB_VERSION}-SE.sql ${MYSQL_CONTAINER_NAME}:/tmp/workplus-se.sql >> ${platform_msg_log} 2>&1;
        docker cp ${WP_DIR}/mysql/temp/calendar-${DB_VERSION}-SE.sql ${MYSQL_CONTAINER_NAME}:/tmp/calendar-se.sql >> ${platform_msg_log} 2>&1;
        docker cp ${WP_DIR}/mysql/temp/workplus_bpm.sql ${MYSQL_CONTAINER_NAME}:/tmp/workplus_bpm.sql >> ${platform_msg_log} 2>&1;
        ##重设数据库表
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/workplus-se.sql;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/calendar-se.sql;"' >> ${platform_msg_log} 2>&1;
        docker exec ${MYSQL_CONTAINER_NAME} sh -c 'exec mysql -uroot -p"$MYSQL_ROOT_PASSWORD" wp_services -e "source /tmp/workplus_bpm.sql;"' >> ${platform_msg_log} 2>&1;

        echo "reinitialize the platform - reset redis related data ..."|tee -a ${platform_msg_log}
        docker exec ${REDIS_CONTAINER_NAME} redis-cli FLUSHALL >> ${platform_msg_log} 2>&1;

        echo "reinitialize the platform - reset mongo related data ..."|tee -a ${platform_msg_log}
        docker exec ${MONGO_CONTAINER_NAME} sh -c "exec mongo 127.0.0.1:27017/tsq -u ${MONGO_USER} -p ${MONGO_PASS} --authenticationDatabase admin --eval 'db.dropDatabase();'" >> ${platform_msg_log} 2>&1;
        docker exec ${MONGO_CONTAINER_NAME} sh -c "exec mongo 127.0.0.1:27017/form -u ${MONGO_USER} -p ${MONGO_PASS} --authenticationDatabase admin --eval 'db.dropDatabase();'" >> ${platform_msg_log} 2>&1;
        docker exec ${MONGO_CONTAINER_NAME} sh -c "exec mongo 127.0.0.1:27017/kaoqin -u ${MONGO_USER} -p ${MONGO_PASS} --authenticationDatabase admin --eval 'db.dropDatabase();'" >> ${platform_msg_log} 2>&1;
     fi
}

check_dapr_status () {
    echo "check dapr health report" >> ${platform_msg_log} 2>&1
    docker exec $KUNLUN_DAPR_CONTAINER_NAME sh -c 'exec java -version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 30 $KUNLUN_DAPR_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       Dapr进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $KUNLUN_DAPR_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $KUNLUN_DAPR_CONTAINER_NAME;
       docker rm $KUNLUN_DAPR_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workplus/kunlun-dapr'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Dapr进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_dapr () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$KUNLUN_DAPR_IMAGE_NAME:$KUNLUN_VERSION" "$KUNLUN_DAPR_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$KUNLUN_DAPR_CONTAINER_NAME");
    RUN_SERVER="true";
    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "DAPR is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
        check_dapr_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(-e "JAVA_OPTS=-Xms512m -Xmx2048m -Duser.timezone=Asia/Shanghai -Duser.language=zh -Duser.region=CN");
        args+=(--name "$KUNLUN_DAPR_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-e "REGISTRY_BACKEND=");  ##不配置表示单机模式,无须依赖zk服务
        args+=("$KUNLUN_DAPR_IMAGE_NAME:$KUNLUN_VERSION");

        echo "create dapr container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create dapr container success"|tee -a ${platform_msg_log} || echo "create dapr container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$KUNLUN_DAPR_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: DAPR not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $KUNLUN_DAPR_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $KUNLUN_DAPR_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $KUNLUN_DAPR_CONTAINER_NAME;
            docker rm $KUNLUN_DAPR_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workplus/kunlun-dapr'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_dapr_status
    fi
}

install_server () {
    download_image "$WP_SERVER_IMAGE_NAME:${WP_VERSION}" "$WP_SERVER_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$WP_SERVER_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "SERVER is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        get_minio_info
        args=();
        args+=(-e "JAVA_OPTS=-Xms512m -Xmx6144m -Duser.timezone=Asia/Shanghai -Duser.language=zh -Duser.region=CN");
        args+=(--name "$WP_SERVER_CONTAINER_NAME");

        if [[ "${WP_VERSION}" == "5.2.0" ]] || [[ "${WP_VERSION}" == "5.5.0" ]] || [[ "${WP_VERSION}" == "6.3.0" ]];then
            args+=(-p ${MBIM_PORT}:${MBIM_PORT});
            args+=(-p ${PCIM_PORT}:${PCIM_PORT});
        fi

        args+=(-v "/etc/localtime:/etc/localtime:ro");
#       args+=(-v "${WP_DIR}/fdfs/:/fdfs");
#       args+=(-e "EXT_OVERLAYFS_LOCALFS_DIR=/fdfs");

        MONGO_SERVER_ID=$(get_container_id "$MONGO_CONTAINER_NAME");
        MONGO_SERVER="";
        if [[ -n ${MONGO_SERVER_ID} ]]; then
            MONGO_SERVER="$MONGO_CONTAINER_NAME";
        fi
        if [[ -n ${MONGO_SERVER} ]]; then
            args+=(-e "EXT_MONGODB_URL=mongodb://${MONGO_USER}:${MONGO_PASS}@${MONGO_SERVER}/admin?rm.nbChannelsPerNode=256");
            args+=(-e "EXT_MONGODB_DATABASE=${MONGO_DATABASE}");
        fi

        MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
        MYSQL_SERVER="";
        if [[ -n ${MYSQL_SERVER_ID} ]]; then
            MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
        fi
        if [[ -n ${MYSQL_SERVER} && ${DB_DRIVER} == "mysql" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=${MYSQL_DATABASE}");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_MYSQL_URL=jdbc:mysql://${MYSQL_SERVER}:3306/${MYSQL_DATABASE}?useSSL=false&characterEncoding=UTF-8&user=${MYSQL_USER}&password=${MYSQL_PASS}&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:mysql://${MYSQL_SERVER}:3306/wp_services_jobs?useSSL=false&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=com.mysql.cj.jdbc.Driver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${MYSQL_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${MYSQL_PASS}");
        fi
        ##神通数据库管理系统
        if [[ ${DB_DRIVER} == "shentong" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=${OTH_DATABASE_SERVICES}");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_SHENTONG_URL=jdbc:oscar://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_SHENTONG_INSTANCE}?user=${OTH_DATABASE_USER}&password=${OTH_DATABASE_PASS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:oscar://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_SHENTONG_INSTANCE}");
            args+=(-e "EXT_QUARTZ_STORE_TABLE_PREFIX=${OTH_DATABASE_SERVICES_JOBS}.qrtz_");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=com.oscar.Driver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${OTH_DATABASE_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${OTH_DATABASE_PASS}");
        fi
        ##达梦数据库管理系统
        if [[ ${DB_DRIVER} == "dm8" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=${OTH_DATABASE_SERVICES}");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_DM8_URL=jdbc:dm://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_DATABASE_SERVICES}?schema=${OTH_DATABASE_SERVICES}&user=${OTH_DATABASE_USER}&password=${OTH_DATABASE_PASS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:dm://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_DATABASE_SERVICES_JOBS}?schema=${OTH_DATABASE_SERVICES_JOBS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=dm.jdbc.driver.DmDriver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${OTH_DATABASE_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${OTH_DATABASE_PASS}");
        fi

        args+=(-e "EXT_QUARTZ_SCHEDULER_ID=AUTO");
        args+=(-e "EXT_QUARTZ_SCHEDULER_NAME=QuartzScheduler");
        args+=(-e "EXT_QUARTZ_THREAD_COUNT=4");
        args+=(-e "EXT_QUARTZ_THREAD_PRIORITY=5");
        args+=(-e "EXT_QUARTZ_JOB_ZONE=Asia/Shanghai");
        args+=(-e "EXT_QUARTZ_JOB_GROUP=default");
        args+=(-e "EXT_QUARTZ_STORE_CLUSTERED=on");
        args+=(-e "EXT_QUARTZ_STORE_CLASS=org.quartz.impl.jdbcjobstore.JobStoreTX");
        args+=(-e "EXT_QUARTZ_STORE_DRIVER=org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
        args+=(-e "EXT_QUARTZ_STORE_MISFIRE_THRESHOLD=60000");
        args+=(-e "EXT_QUARTZ_DATASOURCE_MAX_IDLE_TIME=180");
        args+=(-e "EXT_QUARTZ_DATASOURCE_MAX_CONNECTIONS=8");

        REDIS_SERVER_ID=$(get_container_id "$REDIS_CONTAINER_NAME");
        REDIS_SERVER="";
        if [[ -n ${REDIS_SERVER_ID} ]]; then
            REDIS_SERVER="$REDIS_CONTAINER_NAME";
        fi
        if [[ -n ${REDIS_SERVER} ]]; then
            args+=(-e "EXT_REDIS_STANDALONE_HOST=${REDIS_SERVER}");
            args+=(-e "EXT_REDIS_STANDALONE_DATABASE=1");
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "fastdfs" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=fastdfs");
        args+=(-e "EXT_OVERLAYFS_FASTDFS_CONNECTIONS=db-fdfs:22222");
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "localfs" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=localfs");
        args+=(-e "EXT_OVERLAYFS_LOCALFS_DIR=/localfs");
        args+=(-v ${WP_DIR}/localfs:/localfs);
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "s3" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=s3");
        args+=(-e "EXT_OVERLAYFS_S3_ACCESS_KEY=${MINIO_ROOT_USER}");
        args+=(-e "EXT_OVERLAYFS_S3_SECRET_KEY=${MINIO_ROOT_PASSWORD}");
        args+=(-e "EXT_OVERLAYFS_S3_ENDPOINT=http://${MINIO_CONTAINER_NAME}:${MINIO_API_PORT}/");
        args+=(-e "EXT_OVERLAYFS_S3_BUCKET_NAME=workplus");
        fi

        args+=(-v ${WP_DIR}/im-ssl/certs.pem:/etc/ssl/certs/certs.pem);
        args+=(-v ${WP_DIR}/im-ssl/certs_java.key:/etc/ssl/certs/certs_java.key);
        args+=(-e "DAPR_APP_HOST=<getHostAddress>");
        args+=(-e "DAPR_APP_PORT=10001");
        args+=(-e "SERVICE_LOG=${WP_LOG}");
        args+=(-e "SERVICE_DB_LOG=warn");
        args+=(-e "SERVICE_HOST=${WP_SERVER_CONTAINER_NAME}");
        args+=(-e "SERVICE_PORT=10000");
        args+=(-e "SERVICE_BIND_HOST=0.0.0.0");
        args+=(-e "SERVICE_BIND_PORT=10000");
        args+=(-e "SESSION_SOCKET_CANONICAL_HOST=${WP_HOST}");
        args+=(-e "SESSION_SOCKET_CANONICAL_PORT=${MBIM_PORT}");
        args+=(-e "SESSION_WEBSOCKET_CANONICAL_HOST=${WP_HOST}");
        args+=(-e "SESSION_WEBSOCKET_CANONICAL_PORT=${PCIM_PORT}");
        args+=(-e "SESSION_SOCKET_SSL_ENABLED=off");
        args+=(-e "SESSION_SOCKET_SSL_VERIFY=off");
        args+=(-e "SESSION_SOCKET_SSL_KEY=/opt/ssl/ss.key");
        args+=(-e "SESSION_SOCKET_SSL_CRT=/opt/ssl/ss.crt");
        args+=(-e "SESSION_WEBSOCKET_SSL_ENABLED=${IM_SSL}");
        args+=(-e "SESSION_WEBSOCKET_SSL_VERIFY=off");
        args+=(-e "SESSION_WEBSOCKET_SSL_KEY=/etc/ssl/certs/certs.pem");
        args+=(-e "SESSION_WEBSOCKET_SSL_CRT=/etc/ssl/certs/certs_java.key");
        args+=(-e "SLOW_LOG=on");
        args+=(-e "SLOW_LOG_TIME=3s");
        args+=(-e "SLOW_LOG_LEVEL=${WP_LOG}");
        args+=(-e "DELIVERY_LOGIC_MI_PUSH_NOISY_CHANNEL=${XIAOMI_PUSH}");
        args+=(-e "DELIVERY_LOGIC_MI_PUSH_QUIETLY_CHANNEL=${XIAOMI_PUSH}");
        args+=(-e "DELIVERY_LOGIC_HW_PUSH_NOISY_CHANNEL=${HUAWEI_PUSH}");
        args+=(-e "DELIVERY_LOGIC_HW_PUSH_QUIETLY_CHANNEL=${HUAWEI_PUSH}");
        args+=(-e "SERVICE_DISCUSSION_MEMBER_LIMIT=500");
        args+=(-e "SESSION_TRANSPORT=${IM_TYPE}");
        args+=(-e "SERVICE_MEDIA_SCAN_ENABLED=on");
        args+=(-e "SERVICE_MEDIA_SCAN_JOB_GROUP=MEDIAS");
        args+=(-e "SERVICE_MEDIA_SCAN_JOB_CRON=0 0/30 1-5 * * ?");
        args+=(-e "SERVICE_MEDIA_SCAN_FILTERS=");
        args+=(-e "SERVICE_MEDIA_SCAN_LIMIT=1000");
        args+=(-e "SERVICE_MEDIA_SCAN_BATCH=200");
        args+=(-e "SERVICE_MEDIA_SCAN_EXPIRED_DAYS=7");
        args+=(-e "SERVICE_MEDIA_CLEAN_ENABLED=on");
        args+=(-e "SERVICE_MEDIA_CLEAN_JOB_GROUP=MEDIAS");
        args+=(-e "SERVICE_MEDIA_CLEAN_JOB_CRON=0 0/30 1-5 * * ?");
        args+=(-e "SERVICE_MEDIA_CLEAN_JOB=media_clean_job");
        args+=(-e "SERVICE_MEDIA_CLEAN_FILTERS=");
        args+=(-e "SERVICE_MEDIA_CLEAN_LIMIT=1000");
        args+=(-e "SERVICE_MEDIA_CLEAN_BATCH=200");
        args+=(-e "SERVICE_MEDIA_CLEAN_EXPIRED_DAYS=7");
        args+=(-e "SERVICE_VOLUME_SCAN_ENABLED=on");
        args+=(-e "SERVICE_VOLUME_SCAN_JOB_GROUP=VOLUMES");
        args+=(-e "SERVICE_VOLUME_SCAN_JOB_CRON=0 0/30 1-5 * * ?");
        args+=(-e "SERVICE_VOLUME_SCAN_FILTERS=");
        args+=(-e "SERVICE_VOLUME_SCAN_LIMIT=1000");
        args+=(-e "SERVICE_VOLUME_SCAN_BATCH=200");
        args+=(-e "SERVICE_VOLUME_SCAN_EXPIRED_DAYS=7");
        args+=(-e "SERVICE_VOLUME_ITEM_SCAN_ENABLED=on");
        args+=(-e "SERVICE_VOLUME_ITEM_SCAN_JOB_GROUP=VOLUMES");
        args+=(-e "SERVICE_VOLUME_ITEM_SCAN_JOB_CRON=0 0/30 1-5 * * ?");
        args+=(-e "SERVICE_VOLUME_ITEM_SCAN_FILTERS=");
        args+=(-e "SERVICE_VOLUME_ITEM_SCAN_LIMIT=1000");
        args+=(-e "SERVICE_VOLUME_ITEM_SCAN_BATCH=200");
        args+=(-e "SERVICE_VOLUME_ITEM_SCAN_EXPIRED_DAYS=7");
        args+=(-e "SERVICE_VOLUME_ITEM_CLEAN_ENABLED=on");
        args+=(-e "SERVICE_VOLUME_ITEM_CLEAN_JOB_GROUP=VOLUMES");
        args+=(-e "SERVICE_VOLUME_ITEM_CLEAN_JOB_CRON=0 0/30 1-5 * * ?");
        args+=(-e "SERVICE_VOLUME_ITEM_CLEAN_FILTERS=");
        args+=(-e "SERVICE_VOLUME_ITEM_CLEAN_LIMIT=1000");
        args+=(-e "SERVICE_VOLUME_ITEM_CLEAN_BATCH=200");
        args+=(-e "SERVICE_VOLUME_ITEM_CLEAN_EXPIRED_DAYS=7");
        args+=(-e "EXT_FFMPEG_ENABLED=off");
        args+=(-e "SERVICE_SYNC_EMPLOYEE_NAME_VIA_USER=on");
        args+=(-e "SERVICE_SYNC_EMPLOYEE_PHONE_VIA_USER=on");
        args+=(-e "SERVICE_SYNC_EMPLOYEE_EMAIL_VIA_USER=on");
        args+=(-e "SERVICE_SYNC_USER_NAME_VIA_EMPLOYEE=on");
        args+=(-e "SERVICE_SYNC_USER_PHONE_VIA_EMPLOYEE=on");
        args+=(-e "SERVICE_SYNC_USER_EMAIL_VIA_EMPLOYEE=on");
        args+=(-e "SERVICE_TOKEN_LEASE_TIME=2592000000");
        args+=(-e "EXT_BOSS_API_GATEWAY=${IDC_URL}");
        args+=(-e "SERVICE_PROBE_ENABLED=on");
        args+=(-e "SERVICE_PROBE_HOST=0.0.0.0");
        args+=(-e "SERVICE_PROBE_PORT=9924");

        if [[ "${WP_VERSION}" == "5.2.0" ]] || [[ "${WP_VERSION}" == "5.5.0" ]] || [[ "${WP_VERSION}" == "6.3.0" ]];then
        args+=(-e "SESSION_SOCKET_BIND_PORT=${MBIM_PORT}");
        args+=(-e "SESSION_WEBSOCKET_BIND_PORT=${PCIM_PORT}");
        else
        args+=(-e "SESSION_SOCKET_BIND_PORT=8120");
        args+=(-e "SESSION_WEBSOCKET_BIND_PORT=8121");
        fi
        args+=("$WP_SERVER_IMAGE_NAME:${WP_VERSION}");

        echo "create server container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create server container success"|tee -a ${platform_msg_log} || echo "create server container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$WP_SERVER_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
           echo -e "\033[1;31m
           ERROR: SERVER not installed.

           建议的排查步骤:
           1.检查容器启动状态: docker ps -a | grep $WP_SERVER_CONTAINER_NAME
           2.检查容器启动日志: docker logs -n 100 $WP_SERVER_CONTAINER_NAME

           建议的解决方案:
           如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
           docker stop $WP_SERVER_CONTAINER_NAME;
           docker rm $WP_SERVER_CONTAINER_NAME;
           docker rmi $(docker images|grep 'workplus/se-server'|awk '{print $3}');
           \033[0m"|tee -a ${platform_err_log}
           exit 1;
        fi
    fi
}

install_http () {
    download_image "$WP_HTTP_IMAGE_NAME:${WP_VERSION}" "$WP_HTTP_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$WP_HTTP_CONTAINER_NAME");
    RUN_SERVER="true";
    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "HTTP is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        get_minio_info
        args=();
        args+=(-e "JAVA_OPTS=-Xms512m -Xmx4096m -Duser.timezone=Asia/Shanghai -Duser.language=zh -Duser.region=CN");
        args+=(--name "$WP_HTTP_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
#       args+=(-v "${WP_DIR}/fdfs/:/fdfs");
#       args+=(-e "EXT_OVERLAYFS_DRIVER=localfs");
#       args+=(-e "EXT_OVERLAYFS_LOCALFS_DIR=/fdfs");
        WP_SERVER_ID=$(get_container_id "$WP_SERVER_CONTAINER_NAME");
        WP_SERVER="";
        if [[ -n ${WP_SERVER_ID} ]]; then
            WP_SERVER="$WP_SERVER_CONTAINER_NAME";
        fi
        if [[ -n ${WP_SERVER} ]]; then
            args+=(-e "SERVICE_PROTOCOL=akka://w6s@${WP_SERVER}:10000");
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "fastdfs" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=fastdfs");
        args+=(-e "EXT_OVERLAYFS_FASTDFS_CONNECTIONS=db-fdfs:22222");
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "localfs" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=localfs");
        args+=(-e "EXT_OVERLAYFS_LOCALFS_DIR=/localfs");
        args+=(-v ${WP_DIR}/localfs:/localfs);
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "s3" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=s3");
        args+=(-e "EXT_OVERLAYFS_S3_ACCESS_KEY=${MINIO_ROOT_USER}");
        args+=(-e "EXT_OVERLAYFS_S3_SECRET_KEY=${MINIO_ROOT_PASSWORD}");
        args+=(-e "EXT_OVERLAYFS_S3_ENDPOINT=http://${MINIO_CONTAINER_NAME}:${MINIO_API_PORT}/");
        args+=(-e "EXT_OVERLAYFS_S3_BUCKET_NAME=workplus");
        fi

        args+=(-e "FALLBACK_LOGIN=on");
        args+=(-e "FALLBACK_LOGIN_PROPERTIES="phone,email"");
        args+=(-e "DAPR_APP_HOST=<getHostAddress>");
        args+=(-e "DAPR_APP_PORT=10002");
        args+=(-e "SERVICE_LOG=${WP_LOG}");
        args+=(-e "SLOW_LOG=on");
        args+=(-e "SLOW_LOG_TIME=3s");
        args+=(-e "SLOW_LOG_LEVEL=${WP_LOG}");
        args+=(-e "SERVICE_SHARE_ORG_TEMPLATE=${url_prefix}://${WP_HOST}:${DASH_PORT}/html/share/index.html#/ORG?id={id}&from={from}");
        args+=(-e "SERVICE_SHARE_USER_TEMPLATE=${url_prefix}://${WP_HOST}:${DASH_PORT}/html/share/index.html#/USER?id={id}&from={from}");
        args+=(-e "SERVICE_SHARE_DISCUSSION_TEMPLATE=${url_prefix}://${WP_HOST}:${DASH_PORT}/html/share/index.html#/DISCUSSION?id={id}&from={from}");
        args+=(-e "SERVICE_SHARE_RELEASE_TEMPLATE=${url_prefix}://${WP_HOST}:${DASH_PORT}/html/share/index.html#/RELEASE?id={id}&from={from}");
        args+=(-e "MESSAGE_SYNC_PERIOD=7d");
        args+=(-e "MESSAGE_SYNC_PER_MAX=200");
        args+=(-e "MESSAGE_SYNC_PER_REQUEST=100");
        args+=(-e "MESSAGE_ROAMING_PERIOD=1095d");
        args+=(-e "MESSAGE_ROAMING_PER_MAX=200");
        args+=(-e "MESSAGE_ROAMING_PER_REQUEST=100");
        args+=(-e "MESSAGE_CONVERSATION_PERIOD=30d");
        args+=(-e "MESSAGE_CONVERSATION_PER_MAX=100");
        args+=(-e "MESSAGE_CONVERSATION_PER_REQUEST=100");
        args+=(-e "EXT_BOSS_API_GATEWAY=${IDC_URL}");
        args+=("$WP_HTTP_IMAGE_NAME:${WP_VERSION}");

        echo "create http container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create http container success"|tee -a ${platform_msg_log} || echo "create http container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$WP_HTTP_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: HTTP not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $WP_HTTP_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $WP_HTTP_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $WP_HTTP_CONTAINER_NAME;
            docker rm $WP_HTTP_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workplus/se-http'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi
    fi
}

install_dash () {
    download_image "$WP_DASH_IMAGE_NAME:${WP_VERSION}" "$WP_DASH_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$WP_DASH_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "DASH is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        get_minio_info
        if ! file_exists ${HOME}/.reginfo; then
            echo $(cat /proc/sys/kernel/random/uuid) > ${HOME}/.reginfo
        fi
        UUID=$(cat ${HOME}/.reginfo)
#       UUID=$(docker run --rm -t -u root -v /dev/mem:/dev/mem:rw,z --privileged registry.baidubce.com/workplus/agent-dmi:3.2 dmidecode -t 1 | grep 'UUID' | awk -F ':' '{print $2}' | sed s/[[:space:]]//g)

        args=();
        args+=(-e "JAVA_OPTS=-Xms512m -Xmx2048m -Duser.timezone=Asia/Shanghai -Duser.language=zh -Duser.region=CN");
        args+=(-e "REGISTRATION_ID=${UUID}");
        args+=(-e "REGISTRATION_HOSTS=${WP_HOST}");
        args+=(-e "REGISTRATION_PORTS=${MBIM_PORT},${PCIM_PORT},${DASH_PORT},${HTTP_PORT}");

        args+=(--name "$WP_DASH_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
#       args+=(-v "${WP_DIR}/fdfs/:/fdfs");
#       args+=(-e "EXT_OVERLAYFS_DRIVER=localfs");
#       args+=(-e "EXT_OVERLAYFS_LOCALFS_DIR=/fdfs");
        args+=(-v "${WP_DIR}/nginx/certs:/opt/certs");

        REDIS_SERVER_ID=$(get_container_id "$REDIS_CONTAINER_NAME");
        REDIS_SERVER="";
        if [[ -n ${REDIS_SERVER_ID} ]]; then
            REDIS_SERVER="$REDIS_CONTAINER_NAME";
        fi
        if [[ -n ${REDIS_SERVER} ]]; then
            args+=(-e "EXT_REDIS_STANDALONE_HOST=${REDIS_SERVER}");
            args+=(-e "EXT_REDIS_STANDALONE_DATABASE=1");
        fi

        WP_SERVER_ID=$(get_container_id "$WP_SERVER_CONTAINER_NAME");
        WP_SERVER="";
        if [[ -n ${WP_SERVER_ID} ]]; then
            WP_SERVER="$WP_SERVER_CONTAINER_NAME";
        fi
        if [[ -n ${WP_SERVER} ]]; then
            args+=(-e "SERVICE_PROTOCOL=akka://w6s@${WP_SERVER}:10000");
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "fastdfs" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=fastdfs");
        args+=(-e "EXT_OVERLAYFS_FASTDFS_CONNECTIONS=db-fdfs:22222");
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "localfs" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=localfs");
        args+=(-e "EXT_OVERLAYFS_LOCALFS_DIR=/localfs");
        args+=(-v ${WP_DIR}/localfs:/localfs);
        fi

        if [[ "${EXT_OVERLAYFS_DRIVER}" == "s3" ]]; then
        args+=(-e "EXT_OVERLAYFS_DRIVER=s3");
        args+=(-e "EXT_OVERLAYFS_S3_ACCESS_KEY=${MINIO_ROOT_USER}");
        args+=(-e "EXT_OVERLAYFS_S3_SECRET_KEY=${MINIO_ROOT_PASSWORD}");
        args+=(-e "EXT_OVERLAYFS_S3_ENDPOINT=http://${MINIO_CONTAINER_NAME}:${MINIO_API_PORT}/");
        args+=(-e "EXT_OVERLAYFS_S3_BUCKET_NAME=workplus");
        fi

        args+=(-e "EXT_FFMPEG_ENABLED=off");
        args+=(-e "FALLBACK_LOGIN=on");
        args+=(-e "FALLBACK_LOGIN_PROPERTIES="phone,email"");
        args+=(-e "DAPR_APP_HOST=<getHostAddress>");
        args+=(-e "DAPR_APP_PORT=10003");
        args+=(-e "SERVICE_LOG=${WP_LOG}");
        args+=(-e "SLOW_LOG=on");
        args+=(-e "SLOW_LOG_TIME=3s");
        args+=(-e "SLOW_LOG_LEVEL=${WP_LOG}");
        args+=(-e "EXT_BOSS_API_GATEWAY=${IDC_URL}");
        args+=(-e "SERVICE_ORDER_SERVER_GATEWAY=https://order.beeworks.cn/ordering");
        args+=(-e "SERVICE_ORDER_SERVER_SECRET=Ami6UhlNhnfrKqz5lmLXW5JDVmn2ruHj");
        args+=("$WP_DASH_IMAGE_NAME:${WP_VERSION}");

        echo "create dash container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create dash container success"|tee -a ${platform_msg_log} || echo "create dash container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$WP_DASH_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: DASH not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $WP_DASH_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $WP_DASH_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $WP_DASH_CONTAINER_NAME;
            docker rm $WP_DASH_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workplus/se-dash'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi
    fi
}

check_calendar_status () {
    echo "check calendar health report" >> ${platform_msg_log} 2>&1
    docker exec $WP_CALENDAR_CONTAINER_NAME sh -c 'exec java -version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 30 $WP_CALENDAR_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       CALENDAR进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $WP_CALENDAR_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $WP_CALENDAR_CONTAINER_NAME;
       docker rm $WP_CALENDAR_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workplus/se-calendar'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "CALENDAR进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_calendar () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$WP_CALENDAR_IMAGE_NAME:${WP_VERSION}" "$WP_CALENDAR_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$WP_CALENDAR_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "CALENDAR is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;

        sleep 10
        check_calendar_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$WP_CALENDAR_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-e "JAVA_OPTS=-Xms512m -Xmx1024m -Duser.timezone=Asia/Shanghai -Duser.language=zh -Duser.region=CN");

        MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
        MYSQL_SERVER="";
        if [[ -n ${MYSQL_SERVER_ID} ]]; then
            MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
        fi
        if [[ -n ${MYSQL_SERVER} && ${DB_DRIVER} == "mysql" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=${MYSQL_DATABASE}");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_MYSQL_URL=jdbc:mysql://${MYSQL_SERVER}:3306/${MYSQL_DATABASE}?useSSL=false&characterEncoding=UTF-8&user=${MYSQL_USER}&password=${MYSQL_PASS}&serverTimezone=Asia/Shanghai");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:mysql://${MYSQL_SERVER}:3306/wp_calendar_jobs?useSSL=false&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=com.mysql.cj.jdbc.Driver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${MYSQL_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${MYSQL_PASS}");
        fi
        if [[ ${DB_DRIVER} == "shentong" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=${OTH_DATABASE_CALENDAR}");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_SHENTONG_URL=jdbc:oscar://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_SHENTONG_INSTANCE}?user=${OTH_DATABASE_USER}&password=${OTH_DATABASE_PASS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:oscar://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_SHENTONG_INSTANCE}");
            args+=(-e "EXT_QUARTZ_STORE_TABLE_PREFIX=${OTH_DATABASE_CALENDAR_JOBS}.qrtz_");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=com.oscar.Driver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${OTH_DATABASE_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${OTH_DATABASE_PASS}");
        fi
        if [[ ${DB_DRIVER} == "dm8" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=${OTH_DATABASE_CALENDAR}");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_DM8_URL=jdbc:dm://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_DATABASE_CALENDAR}?schema=${OTH_DATABASE_CALENDAR}&user=${OTH_DATABASE_USER}&password=${OTH_DATABASE_PASS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:dm://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_DATABASE_CALENDAR_JOBS}?schema=${OTH_DATABASE_CALENDAR_JOBS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=dm.jdbc.driver.DmDriver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${OTH_DATABASE_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${OTH_DATABASE_PASS}");
        fi

        args+=(-e "EXT_QUARTZ_SCHEDULER_ID=AUTO");
        args+=(-e "EXT_QUARTZ_SCHEDULER_NAME=QuartzScheduler");
        args+=(-e "EXT_QUARTZ_THREAD_COUNT=4");
        args+=(-e "EXT_QUARTZ_THREAD_PRIORITY=5");
        args+=(-e "EXT_QUARTZ_JOB_ZONE=Asia/Shanghai");
        args+=(-e "EXT_QUARTZ_JOB_GROUP=default");
        args+=(-e "EXT_QUARTZ_STORE_CLUSTERED=on");
        args+=(-e "EXT_QUARTZ_STORE_CLASS=org.quartz.impl.jdbcjobstore.JobStoreTX");
        args+=(-e "EXT_QUARTZ_STORE_DRIVER=org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
        args+=(-e "EXT_QUARTZ_STORE_MISFIRE_THRESHOLD=60000");
        args+=(-e "EXT_QUARTZ_DATASOURCE_MAX_IDLE_TIME=180");
        args+=(-e "EXT_QUARTZ_DATASOURCE_MAX_CONNECTIONS=8");

        WP_SERVER_ID=$(get_container_id "$WP_SERVER_CONTAINER_NAME");
        WP_SERVER="";
        if [[ -n ${WP_SERVER_ID} ]]; then
            WP_SERVER="$WP_SERVER_CONTAINER_NAME";
        fi
        if [[ -n ${WP_SERVER} ]]; then
            args+=(-e "SERVICE_PROTOCOL=akka://w6s@${WP_SERVER}:10000");
        fi

        args+=(-e "DAPR_APP_HOST=<getHostAddress>");
        args+=(-e "DAPR_APP_PORT=10004");
        args+=(-e "SERVICE_LOG=${WP_LOG}");
        args+=(-e "SERVICE_DB_LOG=warn");
        args+=(-e "SLOW_LOG=on");
        args+=(-e "SLOW_LOG_TIME=3s");
        args+=(-e "SLOW_LOG_LEVEL=${WP_LOG}");
        args+=("$WP_CALENDAR_IMAGE_NAME:${WP_VERSION}");

        echo "create calendar container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create calendar container success"|tee -a ${platform_msg_log} || echo "create calendar container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$WP_CALENDAR_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: CALENDAR not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $WP_CALENDAR_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $WP_CALENDAR_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $WP_CALENDAR_CONTAINER_NAME;
            docker rm $WP_CALENDAR_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workplus/se-calendar'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_calendar_status
    fi
}

check_auditlog_status () {
    echo "check auditlog health report" >> ${platform_msg_log} 2>&1
    docker exec $WP_AUDITLOG_CONTAINER_NAME sh -c 'exec java -version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 30 $WP_AUDITLOG_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       AUDITLOG进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $WP_AUDITLOG_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $WP_AUDITLOG_CONTAINER_NAME;
       docker rm $WP_AUDITLOG_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workplus/se-auditlog'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "AUDITLOG进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_auditlog () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$WP_AUDITLOG_IMAGE_NAME:${WP_VERSION}" "$WP_AUDITLOG_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$WP_AUDITLOG_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "AUDITLOG is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;

        sleep 10
        check_auditlog_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$WP_AUDITLOG_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-e "JAVA_OPTS=-Xms512m -Xmx1024m -Duser.timezone=Asia/Shanghai -Duser.language=zh -Duser.region=CN");

        MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
        MYSQL_SERVER="";
        if [[ -n ${MYSQL_SERVER_ID} ]]; then
            MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
        fi
        if [[ -n ${MYSQL_SERVER} && ${DB_DRIVER} == "mysql" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=wp_auditlog");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_MYSQL_URL=jdbc:mysql://${MYSQL_SERVER}:3306/wp_auditlog?useSSL=false&characterEncoding=UTF-8&user=${MYSQL_USER}&password=${MYSQL_PASS}&serverTimezone=Asia/Shanghai");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:mysql://${MYSQL_SERVER}:3306/wp_auditlog_jobs?useSSL=false&characterEncoding=UTF-8&allowPublicKeyRetrieval=true&serverTimezone=Asia/Shanghai");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=com.mysql.cj.jdbc.Driver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${MYSQL_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${MYSQL_PASS}");
        fi
        if [[ ${DB_DRIVER} == "shentong" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=${OTH_DATABASE_AUDITLOG}");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_SHENTONG_URL=jdbc:oscar://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_SHENTONG_INSTANCE}?user=${OTH_DATABASE_USER}&password=${OTH_DATABASE_PASS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:oscar://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_SHENTONG_INSTANCE}");
            args+=(-e "EXT_QUARTZ_STORE_TABLE_PREFIX=${OTH_DATABASE_AUDITLOG_JOBS}.qrtz_");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=com.oscar.Driver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${OTH_DATABASE_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${OTH_DATABASE_PASS}");
        fi
        if [[ ${DB_DRIVER} == "dm8" ]]; then
            args+=(-e "EXT_DB_DRIVER=${DB_DRIVER}");
            args+=(-e "EXT_DB_TABLE_SCHEMA=${OTH_DATABASE_AUDITLOG}");
            args+=(-e "EXT_DB_TABLE_SETUP=${DB_SETUP}");
            args+=(-e "EXT_DB_DM8_URL=jdbc:dm://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_DATABASE_AUDITLOG}?schema=${OTH_DATABASE_AUDITLOG}&user=${OTH_DATABASE_USER}&password=${OTH_DATABASE_PASS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_URL=jdbc:dm://${OTH_DATABASE_HOST}:${OTH_DATABASE_PORT}/${OTH_DATABASE_AUDITLOG_JOBS}?schema=${OTH_DATABASE_AUDITLOG_JOBS}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_DRIVER=dm.jdbc.driver.DmDriver");
            args+=(-e "EXT_QUARTZ_DATASOURCE_USERNAME=${OTH_DATABASE_USER}");
            args+=(-e "EXT_QUARTZ_DATASOURCE_PASSWORD=${OTH_DATABASE_PASS}");
        fi

        args+=(-e "EXT_QUARTZ_SCHEDULER_ID=AUTO");
        args+=(-e "EXT_QUARTZ_SCHEDULER_NAME=QuartzScheduler");
        args+=(-e "EXT_QUARTZ_THREAD_COUNT=4");
        args+=(-e "EXT_QUARTZ_THREAD_PRIORITY=5");
        args+=(-e "EXT_QUARTZ_JOB_ZONE=Asia/Shanghai");
        args+=(-e "EXT_QUARTZ_JOB_GROUP=default");
        args+=(-e "EXT_QUARTZ_STORE_CLUSTERED=on");
        args+=(-e "EXT_QUARTZ_STORE_CLASS=org.quartz.impl.jdbcjobstore.JobStoreTX");
        args+=(-e "EXT_QUARTZ_STORE_DRIVER=org.quartz.impl.jdbcjobstore.StdJDBCDelegate");
        args+=(-e "EXT_QUARTZ_STORE_MISFIRE_THRESHOLD=60000");
        args+=(-e "EXT_QUARTZ_DATASOURCE_MAX_IDLE_TIME=180");
        args+=(-e "EXT_QUARTZ_DATASOURCE_MAX_CONNECTIONS=8");

        WP_SERVER_ID=$(get_container_id "$WP_SERVER_CONTAINER_NAME");
        WP_SERVER="";
        if [[ -n ${WP_SERVER_ID} ]]; then
            WP_SERVER="$WP_SERVER_CONTAINER_NAME";
        fi
        if [[ -n ${WP_SERVER} ]]; then
            args+=(-e "SERVICE_PROTOCOL=akka://w6s@${WP_SERVER}:10000");
        fi

        args+=(-e "DAPR_HOST=kunlun-dapr");
        args+=(-e "DAPR_APP_HOST=<getHostAddress>");
        args+=(-e "DAPR_APP_PORT=10005");
        args+=(-e "SERVICE_PORT=20001");
        args+=(-e "SERVICE_LOG=${WP_LOG}");
        args+=(-e "SERVICE_DB_LOG=warn");
        args+=(-e "SLOW_LOG=on");
        args+=(-e "SLOW_LOG_TIME=3s");
        args+=(-e "SLOW_LOG_LEVEL=${WP_LOG}");
        args+=("$WP_AUDITLOG_IMAGE_NAME:${WP_VERSION}");

        echo "create auditlog container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create auditlog container success"|tee -a ${platform_msg_log} || echo "create auditlog container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$WP_AUDITLOG_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: AUDITLOG not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $WP_AUDITLOG_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $WP_AUDITLOG_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $WP_AUDITLOG_CONTAINER_NAME;
            docker rm $WP_AUDITLOG_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workplus/se-auditlog'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_auditlog_status
    fi
}

check_bpm_status () {
    echo "check bpm health report" >> ${platform_msg_log} 2>&1
    docker exec $APP_BPM_CONTAINER_NAME sh -c 'exec java -version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 100 $APP_BPM_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP BPM进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $APP_BPM_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $APP_BPM_CONTAINER_NAME;
       docker rm $APP_BPM_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/app-bpm'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Bpm进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_app_bpm () {
    download_image "$APP_BPM_IMAGE_NAME:$APP_BPM_IMAGE_TAG" "$APP_BPM_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$APP_BPM_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "APP BPM is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;

        sleep 10
        check_bpm_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$APP_BPM_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-v "${WP_DIR}/bpm/logs:/usr/local/tomcat/logs");
        args+=(-e "WORKPLUS_DEPLOY_TYPE=private");
        args+=(-e "IO_WORKPLUS_API_URL=http://wp-http:9000/v1");
        args+=(-e "WEBSITE_ADDR=${url_prefix}://${WP_HOST}:${HTML_PORT}");
        ##2.6.7版本新增参数(支持与form连通,支持许可证控制)
        args+=(-e "DYNAFORM_SECRET=4DCt1F6JZQNTXMboq9FN");

        MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
        MYSQL_SERVER="";
        if [[ -n ${MYSQL_SERVER_ID} ]]; then
            MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
        fi
        if [[ -n ${MYSQL_SERVER} ]]; then
            args+=(-e "JDBC_HOST=${MYSQL_SERVER}");
            args+=(-e "JDBC_PORT=3306");
            args+=(-e "JDBC_DB_NAME=${MYSQL_DATABASE}");
            args+=(-e "JDBC_USERNAME=${MYSQL_USER}");
            args+=(-e "JDBC_PASSWORD=${MYSQL_PASS}");
        fi

        args+=(-e "REDIS_MODE=single");
        args+=(-e "REDIS_HOST=$REDIS_CONTAINER_NAME");
        args+=(-e "REDIS_POST=6379");
        args+=(-e "REDIS_DB=10");
        args+=(-e "REDIS_PASSWORD=");
        args+=(-e "REDIS_SENTINEL_MASTER=mymaster");
        args+=(-e "REDIS_SENTINEL_NODES=");

        args+=("$APP_BPM_IMAGE_NAME:$APP_BPM_IMAGE_TAG");

        echo "create bpm container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create bpm container success"|tee -a ${platform_msg_log} || echo "create bpm container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$APP_BPM_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP BPM not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $APP_BPM_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $APP_BPM_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $APP_BPM_CONTAINER_NAME;
            docker rm $APP_BPM_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/app-bpm'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        echo "reload bpm process - waiting for it ...";
        sleep_time 60
        docker restart $APP_BPM_CONTAINER_NAME >> /dev/null;

        sleep 15
        check_bpm_status
    fi
}

install_bpm_intermediary () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$BPM_INTERMEDIARY_IMAGE_NAME:$BPM_INTERMEDIARY_IMAGE_TAG" "$BPM_INTERMEDIARY_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$BPM_INTERMEDIARY_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "BPM INTERMEDIARY is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(-e "PROFILES_ACTIVE=docker");
        MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");

        MYSQL_SERVER="";
        if [[ -n ${MYSQL_SERVER_ID} ]]; then
            MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
        fi
        if [[ -n ${MYSQL_SERVER} ]]; then
            args+=(-e "MYSQL_HOST=${MYSQL_SERVER}");
            args+=(-e "MYSQL_POST=3306");
            args+=(-e "MYSQL_DB_NAME=${MYSQL_DATABASE}");
            args+=(-e "MYSQL_USERNAME=${MYSQL_USER}");
            args+=(-e "MYSQL_PASSWORD=${MYSQL_PASS}");
        fi

        REDIS_SERVER_ID=$(get_container_id "$REDIS_CONTAINER_NAME");
        REDIS_SERVER="";
        if [[ -n ${REDIS_SERVER_ID} ]]; then
            REDIS_SERVER="$REDIS_CONTAINER_NAME";
        fi
        if [[ -n ${REDIS_SERVER} ]]; then
            args+=(-e "PROFILES_ACTIVE=docker");
            args+=(-e "REDIS_MODE=single");
            args+=(-e "REDIS_HOST=${REDIS_SERVER}");
            args+=(-e "REDIS_PORT=6379");
            args+=(-e "REDIS_DATABASE=10");
            args+=(-e "REDIS_PASSWORD=");
        fi
        args+=(--name "$BPM_INTERMEDIARY_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=("$BPM_INTERMEDIARY_IMAGE_NAME:$BPM_INTERMEDIARY_IMAGE_TAG");

        echo "create bpm_intermediary container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create bpm_intermediary container success"|tee -a ${platform_msg_log} || echo "create bpm_intermediary container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$BPM_INTERMEDIARY_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: BPM INTERMEDIARY not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $BPM_INTERMEDIARY_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $BPM_INTERMEDIARY_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $BPM_INTERMEDIARY_CONTAINER_NAME;
            docker rm $BPM_INTERMEDIARY_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/bpm-intermediary'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi
    fi
}

check_form_status () {
    echo "check form health report" >> ${platform_msg_log} 2>&1
    docker exec $APP_FORM_CONTAINER_NAME sh -c 'exec java -version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 100 $APP_FORM_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP FORM进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $APP_FORM_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $APP_FORM_CONTAINER_NAME;
       docker rm $APP_FORM_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/app-form'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "form进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_app_form () {
    download_image "$APP_FORM_IMAGE_NAME:$APP_FORM_IMAGE_TAG" "$APP_FORM_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$APP_FORM_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "APP FORM is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
        check_form_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$APP_FORM_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-v "${WP_DIR}/form/logs:/dynaform/log");

        MONGO_SERVER_ID=$(get_container_id "$MONGO_CONTAINER_NAME");
        MONGO_SERVER="";
        if [[ -n ${MONGO_SERVER_ID} ]]; then
            MONGO_SERVER="$MONGO_CONTAINER_NAME";
        fi
        if [[ -n ${MONGO_SERVER} ]]; then
            ##2.6.3版本参数
#           args+=(-e "MONGO_HOSTS=${MONGO_SERVER}:27017");
#           args+=(-e "MONGO_AUTHENTICATION_DBNAME=admin");
#           args+=(-e "MONGO_DBNAME=form");
#           args+=(-e "MONGO_USERNAME=${MONGO_USER}");
#           args+=(-e "MONGO_PASSWORD=${MONGO_PASS}");
#           args+=(-e "MONGO_CREDENTIALS_DBNAME=admin");
#           args+=(-e "MONGO_CREDENTIALS_USER=${MONGO_USER}");
#           args+=(-e "MONGO_CREDENTIALS_PWD=${MONGO_PASS}");
            ##2.6.6版本参数
            args+=(-e "MONGO_URL=mongodb://${MONGO_USER}:${MONGO_PASS}@${MONGO_SERVER}:27017/form?authSource=admin&rm.nbChannelsPerNode=256&rm.failover=100:5x2.0");
            args+=(-e "DB_NAME=form");
            args+=(-e "MAIL_USERNAME=dynaformadmin@mail.com");
            args+=(-e "MAIL_PASSWORD=000000");
            args+=(-e "MAIL_FORM=dynaformadmin");
            ##2.6.8版本新增参数(支持与bpm连通,支持许可证控制)
            args+=(-e "FLOW_URL=${url_prefix}://${WP_HOST}:${HTML_PORT}");
#           args+=(-e "FLOW_URL=http://${APP_HTML_CONTAINER_NAME}:8000");
            args+=(-e "FLOW_SECRET=4DCt1F6JZQNTXMboq9FN");
#           args+=(-e "SMS_SIGN_NAME=深圳恒拓高科信息技术");
#           args+=(-e "SMS_TEMPLATE=SMS_489300019");
#           args+=(-e "SMS_REGION=cn-shenzhen");
#           args+=(-e "SMS_ACCESS=LTAI5t75jRAmdnpxCCaa12dY");
#           args+=(-e "SMS_SECRET=g0iynQIvXsImOBVGOXxz6f9wDMGANv");
            args+=(-e "FLOW_API_URL=");
            args+=(-e "SMS_SIGN_NAME=");
            args+=(-e "SMS_TEMPLATE=");
            args+=(-e "SMS_REGION=");
            args+=(-e "SMS_ACCESS=");
            args+=(-e "SMS_SECRET=");
        fi

        args+=(-e "APP_DEPLOYMENT_TYPE=workplus");
        args+=(-e "IO_WORKPLUS_API_URL=http://wp-http:9000/v1");
        args+=(-e "WEBSITE_ADDR=${url_prefix}://${WP_HOST}:${HTML_PORT}");
        args+=("$APP_FORM_IMAGE_NAME:$APP_FORM_IMAGE_TAG");

        echo "create form container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create form container success"|tee -a ${platform_msg_log} || echo "create form container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$APP_FORM_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP FORM not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $APP_FORM_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $APP_FORM_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $APP_FORM_CONTAINER_NAME;
            docker rm $APP_FORM_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/app-form'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_form_status
    fi
}

check_tsq_status () {
    echo "check tsq health report" >> ${platform_msg_log} 2>&1
    docker exec $APP_TSQ_CONTAINER_NAME sh -c 'exec node -v' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 50 $APP_TSQ_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP TSQ进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $APP_TSQ_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $APP_TSQ_CONTAINER_NAME;
       docker rm $APP_TSQ_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/app-tsq'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Tsq进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_app_tsq () {
    download_image "$APP_TSQ_IMAGE_NAME:$APP_TSQ_IMAGE_TAG" "$APP_TSQ_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$APP_TSQ_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "APP TSQ is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
        check_tsq_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$APP_TSQ_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-e "API_SERVER_PUBLIC=${url_prefix}://${WP_HOST}:${HTTP_PORT}/v1");   #此API接口用于客户端调用,需要配置外部地址
        args+=("$APP_TSQ_IMAGE_NAME:$APP_TSQ_IMAGE_TAG");

        echo "create tsq container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create tsq container success"|tee -a ${platform_msg_log} || echo "create tsq container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$APP_TSQ_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP TSQ not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $APP_TSQ_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $APP_TSQ_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $APP_TSQ_CONTAINER_NAME;
            docker rm $APP_TSQ_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/app-tsq'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_tsq_status
    fi
}

check_kaoqin_status () {
    echo "check kaoqin health report" >> ${platform_msg_log} 2>&1
    docker exec $APP_KAOQIN_CONTAINER_NAME sh -c 'exec node -v' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 50 $APP_KAOQIN_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP KAOQIN进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $APP_KAOQIN_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $APP_KAOQIN_CONTAINER_NAME;
       docker rm $APP_KAOQIN_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/app-kaoqin'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Kaoqin进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_app_kaoqin () {
    download_image "$APP_KAOQIN_IMAGE_NAME:$APP_KAOQIN_IMAGE_TAG" "$APP_KAOQIN_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$APP_KAOQIN_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "APP Kaoqin is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
        check_kaoqin_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$APP_KAOQIN_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-v "${WP_DIR}/kaoqin/logs:/root/.pm2/logs");
        args+=(--user "$(id -u):$(id -g)")

        MONGO_SERVER_ID=$(get_container_id "$MONGO_CONTAINER_NAME");
        MONGO_SERVER="";
        if [[ -n ${MONGO_SERVER_ID} ]]; then
            MONGO_SERVER="$MONGO_CONTAINER_NAME";
        fi
        if [[ -n ${MONGO_SERVER} ]]; then
            args+=(-e "MONGO_HOSTS=${MONGO_SERVER}:27017");
            args+=(-e "MONGO_AUTHENTICATION_DBNAME=admin");
            args+=(-e "MONGO_DBNAME=kaoqin");
            args+=(-e "MONGO_USERNAME=${MONGO_USER}");
            args+=(-e "MONGO_PASSWORD=${MONGO_PASS}");
            args+=(-e "TZ=Asia/Shanghai");
        fi
#       args+=(-e "IO_WORKPLUS_API_URL=${url_prefix}://${WP_HOST}:${HTTP_PORT}/v1/");
        args+=(-e "IO_WORKPLUS_API_URL=http://wp-http:9000/v1");   ##此API接口用于应用内部单点登录,可配容器地址;客户端调的API接口配置在数据库;
        args+=(-e "WEBSITE_ADDR=${url_prefix}://${WP_HOST}:${HTML_PORT}");
        args+=("$APP_KAOQIN_IMAGE_NAME:$APP_KAOQIN_IMAGE_TAG");

        echo "create kaoqin container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create kaoqin container success"|tee -a ${platform_msg_log} || echo "create kaoqin container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$APP_KAOQIN_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP KAOQIN not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $APP_KAOQIN_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $APP_KAOQIN_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $APP_KAOQIN_CONTAINER_NAME;
            docker rm $APP_KAOQIN_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/app-kaoqin'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_kaoqin_status
    fi
}

check_meetapi_status () {
    echo "check meetapi health report" >> ${platform_msg_log} 2>&1
    docker exec $MEETAPI_CONTAINER_NAME sh -c 'exec java --version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 100 $MEETAPI_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP MEETAPI进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $MEETAPI_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $MEETAPI_CONTAINER_NAME;
       docker rm $MEETAPI_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/meet-backend'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Meetapi进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_meet_api () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$MEETAPI_IMAGE_NAME:$MEETAPI_IMAGE_TAG" "$MEETAPI_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$MEETAPI_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "MEET API is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;

        sleep 10
        check_meetapi_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$MEETAPI_CONTAINER_NAME");
        args+=(-e "TZ=Asia/Shanghai");
        args+=(-e "PROFILES_ACTIVE=core,meet");
        args+=(-p ${MEETAPI_PORT}:${MEETAPI_PORT});
        args+=(-e "MEET_ENGINE_BASE_URL=http://${LANIP}:9980");  ##此两个参数优先从数据库读取
        args+=(-e "MEET_ENGINE_ACCESS_TOKEN=12213213");          ##如果数据库没有则读此两参数
        args+=(-e "MEETING_PASSWORD_ENCRYPTION_KEY=vuHmdPHvjpe0YUDo1jXDXJ8s1j/eSWTtbaYSOWPesBw=");

        MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
        MYSQL_SERVER="";
        if [[ -n ${MYSQL_SERVER_ID} ]]; then
            MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
            docker exec ${MYSQL_SERVER} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" -e \"create database ${MEETAPI_DATABASE};\"" > /dev/null 2>&1;
            docker exec ${MYSQL_SERVER} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" -e \"GRANT ALL PRIVILEGES ON *.* TO 'workplus'@'%';\"" > /dev/null 2>&1;
            docker cp ${WP_DIR}/mysql/temp/workplus_meet_init.sql ${MYSQL_SERVER}:/tmp/ > /dev/null 2>&1;
            docker exec ${MYSQL_SERVER} sh -c "exec mysql -uroot -p\"$MYSQL_ROOT_PASSWORD\" ${MEETAPI_DATABASE} -e \"source /tmp/workplus_meet_init.sql;\"" > /dev/null 2>&1;
        fi
        if [[ -n ${MYSQL_SERVER} ]]; then
            args+=(-e "MYSQL_HOST=${MYSQL_SERVER}");
            args+=(-e "MYSQL_POST=3306");
            args+=(-e "MYSQL_USERNAME=${MYSQL_USER}");
            args+=(-e "MYSQL_PASSWORD=${MYSQL_PASS}");
            args+=(-e "MYSQL_DB_NAME=${MEETAPI_DATABASE}");
        fi

        REDIS_SERVER_ID=$(get_container_id "$REDIS_CONTAINER_NAME");
        REDIS_SERVER="";
        if [[ -n ${REDIS_SERVER_ID} ]]; then
            REDIS_SERVER="$REDIS_CONTAINER_NAME";
        fi
        if [[ -n ${REDIS_SERVER} ]]; then
            args+=(-e "REDIS_HOST=${REDIS_SERVER}");
            args+=(-e "REDIS_PORT=6379");
            args+=(-e "REDIS_PASSWORD=");
        fi
        args+=("$MEETAPI_IMAGE_NAME:$MEETAPI_IMAGE_TAG");

        echo "create meet-api container"|tee -a ${platform_msg_log}
        docker run --cpus="2" --memory="1g" --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create meet-api container success"|tee -a ${platform_msg_log} || echo "create meet-api container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$MEETAPI_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP MEETAPI not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $MEETAPI_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $MEETAPI_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $MEETAPI_CONTAINER_NAME;
            docker rm $MEETAPI_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/meet-backend'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_meetapi_status
    fi
}

check_html_status () {
    echo "check html health report" >> ${platform_msg_log} 2>&1
    docker exec $APP_HTML_CONTAINER_NAME sh -c 'exec nginx -v' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 30 $APP_HTML_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP HTML进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $APP_HTML_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $APP_HTML_CONTAINER_NAME;
       docker rm $APP_HTML_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/app-html'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Html进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_app_html () {
    download_image "$APP_HTML_IMAGE_NAME:$APP_HTML_IMAGE_TAG" "$APP_HTML_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$APP_HTML_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "APP HTML is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
        check_html_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$APP_HTML_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
#       args+=(-v ${WP_DIR}/html/nginx.conf:/etc/nginx/nginx.conf);
        args+=(--link "$APP_FORM_CONTAINER_NAME:dynaform");
        args+=(--link "$APP_BPM_CONTAINER_NAME:bpm");
        args+=("$APP_HTML_IMAGE_NAME:$APP_HTML_IMAGE_TAG");

        echo "create html container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create html container success"|tee -a ${platform_msg_log} || echo "create html container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$APP_HTML_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP HTML not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $APP_HTML_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $APP_HTML_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $APP_HTML_CONTAINER_NAME;
            docker rm $APP_HTML_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/app-html'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        docker cp $APP_HTML_CONTAINER_NAME:/etc/nginx/nginx.conf ${WP_DIR}/html/ > /dev/null 2>&1
        check_html_status
    fi
}

check_sync_status () {
    echo "check sync health report" >> ${platform_msg_log} 2>&1
    docker exec $APP_SYNC_CONTAINER_NAME sh -c 'exec java -version' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 50 $APP_SYNC_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP SYNC进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $APP_SYNC_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $APP_SYNC_CONTAINER_NAME;
       docker rm $APP_SYNC_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/app-sync'|awk '{print $3}');
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Sync进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_app_sync () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$APP_SYNC_IMAGE_NAME:$APP_SYNC_IMAGE_TAG" "$APP_SYNC_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$APP_SYNC_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "APP SYNC is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
        check_sync_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$APP_SYNC_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-e "PROFILES_ACTIVE=prod");
#       args+=(-e "SERVER_PORT=9010");
        args+=(-e "WOKRPLUS_API_SERVER=http://wp-http:9000/v1");
        MYSQL_SERVER_ID=$(get_container_id "$MYSQL_CONTAINER_NAME");
        MYSQL_SERVER="";
        if [[ -n ${MYSQL_SERVER_ID} ]]; then
            MYSQL_SERVER="$MYSQL_CONTAINER_NAME";
        fi
        if [[ -n ${MYSQL_SERVER} ]]; then
            args+=(-e "MYSQL_HOST=${MYSQL_SERVER}");
            args+=(-e "MYSQL_POST=3306");
            args+=(-e "MYSQL_DB_NAME=${MYSQL_DATABASE}");
            args+=(-e "MYSQL_USERNAME=${MYSQL_USER}");
            args+=(-e "MYSQL_PASSWORD=${MYSQL_PASS}");
        fi
        args+=("$APP_SYNC_IMAGE_NAME:$APP_SYNC_IMAGE_TAG");

        echo "create sync container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create sync container success"|tee -a ${platform_msg_log} || echo "create sync container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$APP_SYNC_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP SYNC not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $APP_SYNC_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $APP_SYNC_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $APP_SYNC_CONTAINER_NAME;
            docker rm $APP_SYNC_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/app-sync'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        docker restart $APP_SYNC_CONTAINER_NAME >> /dev/null;
        sleep 10
        check_sync_status
    fi
}

install_app_preview () {
    download_image "$APP_PREVIEW_IMAGE_NAME:$APP_PREVIEW_IMAGE_TAG" "$APP_PREVIEW_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$APP_PREVIEW_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "APP PREVIEW is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$APP_PREVIEW_CONTAINER_NAME");
        args+=(-v "/etc/localtime:/etc/localtime:ro");
        args+=(-e "OLDPWD=/opt/kkFileView-4.4.0");
        args+=(-e "KK_CONTEXT_PATH=/preview");
	      args+=(-e "KK_BASE_URL=${url_prefix}://${WP_HOST}:${HTML_PORT}/preview/");
        args+=("$APP_PREVIEW_IMAGE_NAME:$APP_PREVIEW_IMAGE_TAG");

        echo "create preview container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create preview container success"|tee -a ${platform_msg_log} || echo "create preview container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$APP_PREVIEW_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP PREVIEW not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $APP_PREVIEW_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $APP_PREVIEW_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $APP_PREVIEW_CONTAINER_NAME;
            docker rm $APP_PREVIEW_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/app-preview'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi
    fi
}

install_app_collabora () {
    download_image "$APP_COLLABORA_IMAGE_NAME:$APP_COLLABORA_IMAGE_TAG" "$APP_COLLABORA_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$APP_COLLABORA_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "APP COLLABORA is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(--name "$APP_COLLABORA_CONTAINER_NAME");
        args+=(-e "TZ=Asia/Shanghai");
        args+=(-e 'username=coladmin');
        ##password 含特殊字符, 使用单引号包裹避免 shell 解析
        args+=(-e 'password=col@2026!@#');
        args+=(-e "lang=zh-CN");
        args+=(-p ${COLLABORA_HOST_PORT}:${COLLABORA_CONTAINER_PORT});
        args+=("$APP_COLLABORA_IMAGE_NAME:$APP_COLLABORA_IMAGE_TAG");
        args+=("--o:ssl.enable=false");
        args+=("--o:ssl.termination=true");
        args+=("--o:logging.level=information");
        args+=("--o:welcome.enable=false");
        args+=("--o:response.always_send_server=false");
        args+=("--o:per_document.always_save_on_exit=true");
        args+=("--o:storage.wopi[@allow]=true");
        args+=("--o:storage.wopi.allow_all_hosts=true");
        args+=("--o:net.frame_ancestors=*");
        args+=("--o:net.content_security_policy=frame-ancestors *");

        echo "create collabora container"|tee -a ${platform_msg_log}
        docker run -d --restart=always --cap-add MKNOD --net ${platform_name} "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create collabora container success"|tee -a ${platform_msg_log} || echo "create collabora container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$APP_COLLABORA_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP COLLABORA not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $APP_COLLABORA_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $APP_COLLABORA_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $APP_COLLABORA_CONTAINER_NAME;
            docker rm $APP_COLLABORA_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workplus/collabora-online'|awk '{print $3}');
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi
    fi
}

check_office_status () {
    echo "check office health report" >> ${platform_msg_log} 2>&1
    docker exec $DOCUMENT_CONTAINER_NAME sh -c 'exec netstat -nltp|grep 8000' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 50 $DOCUMENT_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP OFFICE进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $DOCUMENT_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $DOCUMENT_CONTAINER_NAME;
       docker rm $DOCUMENT_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/documentserver-ce'|awk '{print $3}');
       rm -rf ${WP_DIR}/office
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Office进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_app_document () {
    if [[ "${reset_https}" == "true" ]] || [[ "${reset_hosts}" == "true" ]] || [[ "${reset_domain}" == "true" ]]; then
       return
    fi
    download_image "$DOCUMENT_IMAGE_NAME:$DOCUMENT_IMAGE_TAG" "$DOCUMENT_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$DOCUMENT_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "Documentserver is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 30
        check_office_status
    fi

    if [ ! -f ${WP_DIR}/office/fonts/Dengb.ttf ];then
        if [ ! -f /tmp/fonts_onlyoffice7.2.tar.gz ];then
            docker cp app-html:/usr/local/src/fonts_onlyoffice7.2.tar.gz /tmp/
        fi
        tar xf /tmp/fonts_onlyoffice7.2.tar.gz -C /tmp/
        /bin/cp -ra /tmp/fonts_onlyoffice7.2/* ${WP_DIR}/office/fonts/
    fi
    echo 'JWT_ENABLED=false' > ${WP_DIR}/office/conf/onlyoffice_config.env;
    if [[ "${RUN_SERVER}" == "true" ]]; then
        args=();
        args+=(-e "TZ=Asia/Shanghai");
        args+=(--name "$DOCUMENT_CONTAINER_NAME");
        args+=(-v ${WP_DIR}/office/logs:/var/log/onlyoffice);
        args+=(-v ${WP_DIR}/office/data:/var/www/onlyoffice/Data);
        args+=(-v ${WP_DIR}/office/lib:/var/lib/onlyoffice);
        args+=(-v ${WP_DIR}/office/db:/var/lib/postgresql);
        args+=(-v ${WP_DIR}/office/fonts:/usr/share/fonts/custom);
        args+=(-v ${WP_DIR}/office/fonts-ds:/var/www/onlyoffice/documentserver/fonts);
        args+=("$DOCUMENT_IMAGE_NAME:$DOCUMENT_IMAGE_TAG");

        echo "create office container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --env-file ${WP_DIR}/office/conf/onlyoffice_config.env --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create office container success"|tee -a ${platform_msg_log} || echo "create office container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$DOCUMENT_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP OFFICE not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $DOCUMENT_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $DOCUMENT_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $DOCUMENT_CONTAINER_NAME;
            docker rm $DOCUMENT_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/documentserver-ce'|awk '{print $3}');
            rm -rf ${WP_DIR}/office
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        echo "update documentserver fonts files, waiting for it ..."
        sleep_time 60

        echo "重设PostgreSQL数据目录权限" >> ${platform_msg_log} 2>&1
        docker cp $DOCUMENT_CONTAINER_NAME:/app/ds/run-document-server.sh /tmp/run-document-server.sh > /dev/null 2>&1;
        sed -i 's/chmod -R 700 ${PG_ROOT}/chmod -R 750 ${PG_ROOT}/g' /tmp/run-document-server.sh > /dev/null 2>&1;
        docker cp /tmp/run-document-server.sh $DOCUMENT_CONTAINER_NAME:/app/ds/run-document-server.sh;
        [ $? -ne 0 ] && echo -e "\n重设PostgreSQL数据目录权限失败"|tee -a ${platform_err_log}

        echo "删除局域网网络无法使用onlyoffice策略" >> ${platform_msg_log} 2>&1
        docker cp $DOCUMENT_CONTAINER_NAME:/etc/onlyoffice/documentserver/default.json /tmp/default.json > /dev/null 2>&1;
        sed -i 's/"allowPrivateIPAddress": false/"allowPrivateIPAddress": true/g' /tmp/default.json > /dev/null 2>&1;
        sed -i 's/"allowMetaIPAddress": false/"allowMetaIPAddress": true/g' /tmp/default.json > /dev/null 2>&1
        sed -i 's/"uncompressed": "50MB",/"uncompressed": "4096MB",/g' /tmp/default.json > /dev/null 2>&1;
        sed -i 's/"uncompressed": "300MB",/"uncompressed": "4096MB",/g' /tmp/default.json > /dev/null 2>&1;
        sed -i 's/"maxDownloadBytes": .*/"maxDownloadBytes": 209715200,/g' /tmp/default.json > /dev/null 2>&1;
        sed -i '/"autoAssembly": {/,/}/ { s/"enable": false,/"enable": true,/; s/"interval": "5m",/"interval": "1m",/; s|"step": "5m"|"step": "1m"|; }' /tmp/default.json > /dev/null 2>&1;
        docker cp /tmp/default.json $DOCUMENT_CONTAINER_NAME:/etc/onlyoffice/documentserver/default.json;
        if [ $? -ne 0 ]; then
          echo -e "\n删除局域网网络无法使用onlyoffice策略失败"|tee -a ${platform_err_log}
          echo -e "\n记录onlyoffice日志1" >> ${platform_err_log} 2>&1;
          docker logs -n 200 $DOCUMENT_CONTAINER_NAME >> ${platform_err_log} 2>&1;
          echo -e "\n记录onlyoffice日志2" >> ${platform_err_log} 2>&1;
          cat ${WP_DIR}/office/logs/documentserver/docservice/out.log >> ${platform_err_log} 2>&1;
        fi

        docker exec $(docker ps|grep 'documentserver'|awk '{print $NF}') sh -c '/usr/bin/documentserver-generate-allfonts.sh' > /dev/null 2>&1;
        echo "update documentserver data files, waiting for it ..."
        sleep_time 60
        docker restart $DOCUMENT_CONTAINER_NAME >> /dev/null;

        sleep 30
        check_office_status

        PrivateIP=$(docker exec $DOCUMENT_CONTAINER_NAME sh -c 'grep "IPAddress" /etc/onlyoffice/documentserver/default.json|grep true'|wc -l)
        if [ ${PrivateIP} -ne 2 ];then
            echo -e "\n$(date +%Y%m%d-%H:%M:%S)\nwarning: allow private ip network access onlyoffice -- failed" | tee -a ${platform_err_log}
            echo -e "\n$(date +%Y%m%d-%H:%M:%S)trying to fix this problem ..." | tee -a ${platform_err_log}
            if [[ "$DOCUMENT_IMAGE_TAG" == 8* ]]; then
               curl -o ${WP_DIR}/office/conf/default_tmp.json http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/onlyofficev8_default.json >> ${platform_err_log} 2>&1
               if [ $? -eq 0 ];then
                  docker cp ${WP_DIR}/office/conf/default_tmp.json $DOCUMENT_CONTAINER_NAME:/etc/onlyoffice/documentserver/default.json >> /dev/null 2>&1;
                  docker restart $DOCUMENT_CONTAINER_NAME >> /dev/null;
                  echo -e "\n$(date +%Y%m%d-%H:%M:%S)check the fix results:" >> ${platform_err_log} 2>&1;
                  docker exec $DOCUMENT_CONTAINER_NAME sh -c 'grep "IPAddress" /etc/onlyoffice/documentserver/default.json' >> ${platform_err_log} 2>&1
               else
                  echo -e "\n$(date +%Y%m%d-%H:%M:%S)trying to fix this problem ... failed" | tee -a ${platform_err_log}
                  echo -e "\n记录onlyoffice日志3" >> ${platform_err_log} 2>&1;
                  docker logs -n 200 $DOCUMENT_CONTAINER_NAME >> ${platform_err_log} 2>&1;
                  echo -e "\n记录onlyoffice日志4" >> ${platform_err_log} 2>&1;
                  cat ${WP_DIR}/office/logs/documentserver/docservice/out.log >> ${platform_err_log} 2>&1;
               fi
            fi
            if [[ "$DOCUMENT_IMAGE_TAG" == 9* ]]; then
               curl -o ${WP_DIR}/office/conf/default_tmp.json http://w6s-docker.oss-cn-shenzhen.aliyuncs.com/onlyofficev9_default.json >> ${platform_err_log} 2>&1
               if [ $? -eq 0 ];then
                  docker cp ${WP_DIR}/office/conf/default_tmp.json $DOCUMENT_CONTAINER_NAME:/etc/onlyoffice/documentserver/default.json >> /dev/null 2>&1;
                  docker restart $DOCUMENT_CONTAINER_NAME >> /dev/null;
                  echo -e "\n$(date +%Y%m%d-%H:%M:%S)check the fix results:" >> ${platform_err_log} 2>&1;
                  docker exec $DOCUMENT_CONTAINER_NAME sh -c 'grep "IPAddress" /etc/onlyoffice/documentserver/default.json' >> ${platform_err_log} 2>&1
               else
                  echo -e "\n$(date +%Y%m%d-%H:%M:%S)trying to fix this problem ... failed" | tee -a ${platform_err_log}
                  echo -e "\n记录onlyoffice日志3" >> ${platform_err_log} 2>&1;
                  docker logs -n 200 $DOCUMENT_CONTAINER_NAME >> ${platform_err_log} 2>&1;
                  echo -e "\n记录onlyoffice日志4" >> ${platform_err_log} 2>&1;
                  cat ${WP_DIR}/office/logs/documentserver/docservice/out.log >> ${platform_err_log} 2>&1;
               fi
            fi
        else
            echo -e "\n$(date +%Y%m%d-%H:%M:%S)\nallow private ip network access onlyoffice -- success" >> ${platform_msg_log} 2>&1;
        fi
    fi
}

check_nginx_status () {
    echo "check nginx health report" >> ${platform_msg_log} 2>&1
    docker exec $NGINX_CONTAINER_NAME sh -c 'exec nginx -v' >> ${platform_msg_log} 2>&1
    if [ $? -ne 0 ];then
       docker logs -n 30 $NGINX_CONTAINER_NAME >> ${platform_err_log} 2>&1
       echo -e "\033[1;31m
       APP NGINX进程状态检测失败,请查看容器状态和错误日志获取失败原因
       错误日志文件: ${platform_err_log}
       查看容器状态: docker ps -a|grep $NGINX_CONTAINER_NAME;

       建议的解决方案:
       如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
       docker stop $NGINX_CONTAINER_NAME;
       docker rm $NGINX_CONTAINER_NAME;
       docker rmi $(docker images|grep 'workapps/nginx'|awk '{print $3}');
       rm -rf ${WP_DIR}/nginx
       \033[0m"|tee -a ${platform_err_log}
    else
       echo "Nginx进程状态检测成功" >> ${platform_msg_log} 2>&1
    fi
}

install_nginx () {
    download_image "$NGINX_IMAGE_NAME:$NGINX_IMAGE_TAG" "$NGINX_CONTAINER_NAME"
    RUN_SERVER_ID=$(get_container_id "$NGINX_CONTAINER_NAME");
    RUN_SERVER="true";

    if [[ -n ${RUN_SERVER_ID} ]]; then
        RUN_SERVER="false";
        echo "Nginx is already installed."
        docker start ${RUN_SERVER_ID} >> /dev/null;
        sleep 10
        docker exec $NGINX_CONTAINER_NAME sh -c "nginx -t && nginx -s reload"
        check_nginx_status
        sleep 10
        check_nginx_status
    fi

    if [[ "${RUN_SERVER}" == "true" ]]; then
        init_nginx_conf
        args=();
        args+=(--name "$NGINX_CONTAINER_NAME");

        if [[ "${WP_VERSION}" == "5.2.0" ]] || [[ "${WP_VERSION}" == "5.5.0" ]] || [[ "${WP_VERSION}" == "6.3.0" ]];then
          #args+=(-p ${DASH_PORT}:${DASH_PORT} -p ${HTTP_PORT}:${HTTP_PORT} -p ${HTML_PORT}:${HTML_PORT} -p 9913:9913 -p 9914:9914 -p ${MEET_PORT}:${MEET_PORT} -p ${UDPS_PORT}:${UDPS_PORT} -p ${DOCS_PORT}:${DOCS_PORT} -p 1936:1936);
          args+=(-p ${DASH_PORT}:${DASH_PORT} -p ${HTTP_PORT}:${HTTP_PORT} -p ${HTML_PORT}:${HTML_PORT} -p 9913:9913 -p 9914:9914 -p ${MEET_PORT}:${MEET_PORT} -p ${UDPS_PORT}:${UDPS_PORT} -p ${DOCS_PORT}:${DOCS_PORT});
        else
          #args+=(-p ${DASH_PORT}:${DASH_PORT} -p ${HTTP_PORT}:${HTTP_PORT} -p ${HTML_PORT}:${HTML_PORT} -p 9913:9913 -p 9914:9914 -p ${MEET_PORT}:${MEET_PORT} -p ${UDPS_PORT}:${UDPS_PORT} -p ${DOCS_PORT}:${DOCS_PORT} -p 1936:1936);
          args+=(-p ${DASH_PORT}:${DASH_PORT} -p ${HTTP_PORT}:${HTTP_PORT} -p ${HTML_PORT}:${HTML_PORT} -p 9913:9913 -p 9914:9914 -p ${MEET_PORT}:${MEET_PORT} -p ${UDPS_PORT}:${UDPS_PORT} -p ${DOCS_PORT}:${DOCS_PORT});
          args+=(-p ${MBIM_PORT}:${MBIM_PORT} -p ${PCIM_PORT}:${PCIM_PORT}); ##6.3.0之后版本使用nginx转发session端口
        fi
        args+=(-v ${WP_DIR}/nginx/nginx.conf:/etc/nginx/nginx.conf);
        args+=(-v ${WP_DIR}/nginx/default.conf:/etc/nginx/conf.d/default.conf);
        args+=(-v ${WP_DIR}/nginx/certs:/etc/nginx/certs);
        args+=(-v ${WP_DIR}/nginx/project:/usr/share/nginx);
        args+=(-v ${WP_DIR}/nginx/logs:/var/log/nginx);
        args+=("$NGINX_IMAGE_NAME:$NGINX_IMAGE_TAG");

        echo "create nginx container"|tee -a ${platform_msg_log}
        docker run --privileged=true --net ${platform_name} -i -t -d --restart=always "${args[@]}"|tee -a ${platform_msg_log};
        [ $? -eq 0 ] && echo "create nginx container success"|tee -a ${platform_msg_log} || echo "create nginx container failed"|tee -a $platform_err_log

        RUN_SERVER_ID=$(get_container_id "$NGINX_CONTAINER_NAME");
        if [[ -z ${RUN_SERVER_ID} ]]; then
            echo -e "\033[1;31m
            ERROR: APP NGINX not installed.

            建议的排查步骤:
            1.检查容器启动状态: docker ps -a | grep $NGINX_CONTAINER_NAME
            2.检查容器启动日志: docker logs -n 100 $NGINX_CONTAINER_NAME

            建议的解决方案:
            如无法定位问题原因, 请卸载此服务后再尝试安装, 卸载命令如下
            docker stop $NGINX_CONTAINER_NAME;
            docker rm $NGINX_CONTAINER_NAME;
            docker rmi $(docker images|grep 'workapps/nginx'|awk '{print $3}');
            rm -rf ${WP_DIR}/nginx
            \033[0m"|tee -a ${platform_err_log}
            exit 1;
        fi

        sleep 10
        check_nginx_status
        sleep 10
        check_nginx_status

    fi
}

check_server_status () {
    echo -e "\ncheck server health report" >> ${platform_msg_log} 2>&1
    server_msg=$(docker exec "$WP_SERVER_CONTAINER_NAME" sh -c 'exec curl -sS --connect-timeout 10 --max-time 15 http://127.0.0.1:9924/_health' 2>&1)
    curl_exit_code=$?

    if [ $curl_exit_code -eq 0 ] && echo "${server_msg}" | grep -q 'Service healthy'; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') Server服务健康状态检查成功：服务正常运行" | tee -a "${platform_msg_log}"
    elif [ $curl_exit_code -ne 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') Server服务健康检查失败：curl命令执行错误（退出码：$curl_exit_code）" | tee -a "${platform_err_log}"
        echo "错误信息：${server_msg}" | tee -a "${platform_err_log}"
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S') Server服务健康状态异常：响应内容不符合预期" | tee -a "${platform_err_log}"
        echo "响应内容：${server_msg}" >> "${platform_err_log}" 2>&1
        echo "$(date '+%Y-%m-%d %H:%M:%S') 正在重载服务修正异常状态, 预估一分钟左右, 请稍后" | tee -a "${platform_err_log}"
        docker restart $WP_SERVER_CONTAINER_NAME
        sleep_time 60

        echo -e "\ncheck server health report second time" >> ${platform_msg_log} 2>&1
        server_msg=$(docker exec "$WP_SERVER_CONTAINER_NAME" sh -c 'exec curl -sS --connect-timeout 10 --max-time 15 http://127.0.0.1:9924/_health' 2>&1)
        curl_exit_code=$?

        if [ $curl_exit_code -ne 0 ] || ! echo "${server_msg}" | grep -q 'Service healthy'; then
           echo "$(date '+%Y-%m-%d %H:%M:%S') 开始记录容器最近30条日志：" | tee -a "${platform_err_log}"
           docker logs -n 50 "$WP_SERVER_CONTAINER_NAME" 2>&1 | tee -a "${platform_err_log}"
           echo "$(date '+%Y-%m-%d %H:%M:%S') 容器日志记录完成" | tee -a "${platform_err_log}"
        fi
    fi
}

check_http_status () {
    echo -e "\ncheck http health report" >> ${platform_msg_log} 2>&1
    server_msg=$(docker exec "$WP_HTTP_CONTAINER_NAME" sh -c 'exec curl -sS --connect-timeout 10 --max-time 15 http://127.0.0.1:9000/_health' 2>&1)
    curl_exit_code=$?

    if [ $curl_exit_code -eq 0 ] && echo "${server_msg}" | grep -q 'Service healthy'; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') Http服务健康状态检查成功：服务正常运行" | tee -a "${platform_msg_log}"
    elif [ $curl_exit_code -ne 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') Http服务健康检查失败：curl命令执行错误（退出码：$curl_exit_code）" | tee -a "${platform_err_log}"
        echo "错误信息：${server_msg}" | tee -a "${platform_err_log}"
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S') Http服务健康状态异常：响应内容不符合预期" | tee -a "${platform_err_log}"
        echo "响应内容：${server_msg}" >> "${platform_err_log}" 2>&1
        echo "$(date '+%Y-%m-%d %H:%M:%S') 正在重载服务修正异常状态, 预估一分钟左右, 请稍后" | tee -a "${platform_err_log}"
        docker restart $WP_HTTP_CONTAINER_NAME
        sleep_time 60

        echo -e "\ncheck http health report second time" >> ${platform_msg_log} 2>&1
        server_msg=$(docker exec "$WP_HTTP_CONTAINER_NAME" sh -c 'exec curl -sS --connect-timeout 10 --max-time 15 http://127.0.0.1:9924/_health' 2>&1)
        curl_exit_code=$?

        if [ $curl_exit_code -ne 0 ] || ! echo "${server_msg}" | grep -q 'Service healthy'; then
           echo "$(date '+%Y-%m-%d %H:%M:%S') 开始记录容器最近30条日志：" | tee -a "${platform_err_log}"
           docker logs -n 50 "$WP_HTTP_CONTAINER_NAME" 2>&1 | tee -a "${platform_err_log}"
           echo "$(date '+%Y-%m-%d %H:%M:%S') 容器日志记录完成" | tee -a "${platform_err_log}"
        fi
    fi
}

check_dash_status () {
    echo -e "\ncheck dash health report" >> ${platform_msg_log} 2>&1
    server_msg=$(docker exec "$WP_DASH_CONTAINER_NAME" sh -c 'exec curl -sS --connect-timeout 10 --max-time 15 http://127.0.0.1:9000/_health' 2>&1)
    curl_exit_code=$?

    if [ $curl_exit_code -eq 0 ] && echo "${server_msg}" | grep -q 'Service healthy'; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') Dash服务健康状态检查成功：服务正常运行" | tee -a "${platform_msg_log}"
    elif [ $curl_exit_code -ne 0 ]; then
        echo "$(date '+%Y-%m-%d %H:%M:%S') Dash服务健康检查失败：curl命令执行错误（退出码：$curl_exit_code）" | tee -a "${platform_err_log}"
        echo "错误信息：${server_msg}" | tee -a "${platform_err_log}"
    else
        echo "$(date '+%Y-%m-%d %H:%M:%S') Dash服务健康状态异常：响应内容不符合预期" | tee -a "${platform_err_log}"
        echo "响应内容：${server_msg}" >> "${platform_err_log}" 2>&1
        echo "$(date '+%Y-%m-%d %H:%M:%S') 正在重载服务修正异常状态, 预估一分钟左右, 请稍后" | tee -a "${platform_err_log}"
        docker restart $WP_DASH_CONTAINER_NAME
        sleep_time 60

        echo -e "\ncheck dash health report second time" >> ${platform_msg_log} 2>&1
        server_msg=$(docker exec "$WP_DASH_CONTAINER_NAME" sh -c 'exec curl -sS --connect-timeout 10 --max-time 15 http://127.0.0.1:9924/_health' 2>&1)
        curl_exit_code=$?

        if [ $curl_exit_code -ne 0 ] || ! echo "${server_msg}" | grep -q 'Service healthy'; then
           echo "$(date '+%Y-%m-%d %H:%M:%S') 开始记录容器最近30条日志：" | tee -a "${platform_err_log}"
           docker logs -n 50 "$WP_DASH_CONTAINER_NAME" 2>&1 | tee -a "${platform_err_log}"
           echo "$(date '+%Y-%m-%d %H:%M:%S') 容器日志记录完成" | tee -a "${platform_err_log}"
        fi
    fi
}

check_interface () {
    echo -e "\nHttp interface failure log:" >> "${platform_err_log}" 2>&1
    echo "说明1：部分场景可能无法获取异常原因, 状态码返回000即表示网络连接失败" >> "${platform_err_log}" 2>&1
    echo "说明2：本次诊断环境为服务器端, 仅供参考, 与客户端环境可能存在网络差异" >> "${platform_err_log}" 2>&1
    check_code=$(curl -i -k -m 15 -o /dev/null -s -w %{http_code}"\n" ${url_prefix}://${WP_HOST}:${DASH_PORT}/_health)
    if [ ${check_code} == "200" ] || [ ${check_code} == "301" ] || [ ${check_code} == "302" ] || [ ${check_code} == "303" ] || [ ${check_code} == "401" ] || [ ${check_code} == "405" ];then
       echo "地址: ${url_prefix}://${WP_HOST}:${DASH_PORT} access seccuss; 状态码Code: ${check_code}" >> "${platform_msg_log}" 2>&1
    else
       echo -e "\n地址: ${url_prefix}://${WP_HOST}:${DASH_PORT} access failed; 状态码Code: ${check_code}" >> "${platform_err_log}" 2>&1
       echo "异常原因:" >> "${platform_err_log}" 2>&1
       timeout 5 bash -c "</dev/tcp/${WP_HOST}/${DASH_PORT}" >> "${platform_err_log}" 2>&1
    fi
    check_code=$(curl -i -k -m 15 -o /dev/null -s -w %{http_code}"\n" ${url_prefix}://${WP_HOST}:${HTTP_PORT}/_health)
    if [ ${check_code} == "200" ] || [ ${check_code} == "301" ] || [ ${check_code} == "302" ] || [ ${check_code} == "303" ] || [ ${check_code} == "401" ] || [ ${check_code} == "405" ];then
       echo "地址: ${url_prefix}://${WP_HOST}:${HTTP_PORT} access seccuss; 状态码Code: ${check_code}" >> "${platform_msg_log}" 2>&1
    else
       echo -e "\n地址: ${url_prefix}://${WP_HOST}:${HTTP_PORT} access failed; 状态码Code: ${check_code}" >> "${platform_err_log}" 2>&1
       echo "异常原因:" >> "${platform_err_log}" 2>&1
       timeout 5 bash -c "</dev/tcp/${WP_HOST}/${HTTP_PORT}" >> "${platform_err_log}" 2>&1
    fi
    check_code=$(curl -i -k -m 15 -o /dev/null -s -w %{http_code}"\n" ${url_prefix}://${WP_HOST}:${HTML_PORT}/pcweb/config.js)
    if [ ${check_code} == "200" ] || [ ${check_code} == "301" ] || [ ${check_code} == "302" ] || [ ${check_code} == "303" ] || [ ${check_code} == "401" ] || [ ${check_code} == "405" ];then
       echo "地址: ${url_prefix}://${WP_HOST}:${HTML_PORT} access seccuss; 状态码Code: ${check_code}" >> "${platform_msg_log}" 2>&1
    else
       echo -e "\n地址: ${url_prefix}://${WP_HOST}:${HTML_PORT} access failed; 状态码Code: ${check_code}" >> "${platform_err_log}" 2>&1
       echo "异常原因:" >> "${platform_err_log}" 2>&1
       timeout 5 bash -c "</dev/tcp/${WP_HOST}/${HTML_PORT}" >> "${platform_err_log}" 2>&1
    fi
    check_code=$(curl -A workplus -i -k -m 15 -o /dev/null -s -w %{http_code}"\n" ${url_prefix}://${WP_HOST}:${DOCS_PORT}/welcome/)
    if [ ${check_code} == "200" ] || [ ${check_code} == "301" ] || [ ${check_code} == "302" ] || [ ${check_code} == "303" ] || [ ${check_code} == "401" ] || [ ${check_code} == "405" ];then
       echo "地址: ${url_prefix}://${WP_HOST}:${DOCS_PORT} access seccuss; 状态码Code: ${check_code}" >> "${platform_msg_log}" 2>&1
    else
       echo -e "\n地址: ${url_prefix}://${WP_HOST}:${DOCS_PORT} access failed; 状态码Code: ${check_code}" >> "${platform_err_log}" 2>&1
       echo "异常原因:" >> "${platform_err_log}" 2>&1
       timeout 5 bash -c "</dev/tcp/${WP_HOST}/${DOCS_PORT}" >> "${platform_err_log}" 2>&1
    fi
#    check_code=$(curl -i -k -m 15 -o /dev/null -s -w %{http_code}"\n" https://${WP_HOST}:${MEET_PORT}/lang/languages.json)
#    if [ ${check_code} == "200" ] || [ ${check_code} == "301" ] || [ ${check_code} == "302" ] || [ ${check_code} == "303" ] || [ ${check_code} == "401" ] || [ ${check_code} == "405" ];then
#       echo "地址: https://${WP_HOST}:${MEET_PORT} access seccuss; 状态码Code: ${check_code}" >> "${platform_msg_log}" 2>&1
#    else
#       echo -e "\n地址: https://${WP_HOST}:${MEET_PORT} access failed; 状态码Code: ${check_code}" >> "${platform_err_log}" 2>&1
#       echo "异常原因:" >> "${platform_err_log}" 2>&1
#       timeout 5 bash -c "</dev/tcp/${WP_HOST}/${MEET_PORT}" >> "${platform_err_log}" 2>&1
#    fi
}

check_sessions () {
    echo -e "\nTcp interface failure log:" >> "${platform_err_log}" 2>&1
    timeout 5 bash -c "</dev/tcp/${WP_HOST}/${MBIM_PORT}" >> "${platform_err_log}" 2>&1 && echo "地址: tcp://${WP_HOST}:${MBIM_PORT} access seccuss;" >> "${platform_msg_log}" 2>&1 || echo "地址: tcp://${WP_HOST}:${MBIM_PORT} connection refused;" >> "${platform_err_log}" 2>&1
    timeout 5 bash -c "</dev/tcp/${WP_HOST}/${PCIM_PORT}" >> "${platform_err_log}" 2>&1 && echo "地址: tcp://${WP_HOST}:${PCIM_PORT} access seccuss;" >> "${platform_msg_log}" 2>&1 || echo "地址: tcp://${WP_HOST}:${PCIM_PORT} connection refused;" >> "${platform_err_log}" 2>&1
}

check_summary () {
    docker exec ${NGINX_CONTAINER_NAME} nginx -s reload
    echo "=============================接口诊断开始============================="
    echo -e "\n正在测试访问地址+各接口连通性, 测试耗时可能需要1-5分钟, 请稍等..." | tee -a "${platform_msg_log}"
    check_interface
    echo -e "\n正在测试访问地址+IM端口连通性, 测试耗时可能需要1-5分钟, 请稍等..." | tee -a "${platform_msg_log}"
    check_sessions
    check_seccuss_msg=$(grep 'access seccuss' "${platform_msg_log}")
    check_error_msg=$(grep -E 'access failed|connection refused' "${platform_err_log}")
    check_error_log=$(grep -A 50 'Http interface failure log' ${platform_err_log})
    if [ -n "${check_error_msg}" ];then
       echo ""
       echo -e "\033[1;31m在服务器本地访问${WP_HOST}异常, 接口响应如下:\033[0m"
       echo -e "${check_error_msg}"
       echo -e "\n详细诊断日志如下:"
       echo -e "${check_error_log}"
       echo -e "\033[1;33m
       异常排查指引:
       1.确认${WP_HOST}是否是真实有效的IP地址或域名地址;
       2.如果${WP_HOST}不是服务器本机地址, 请检查是否经过了防火墙限制;
       3.如果${WP_HOST}是云服务器公网地址, 请检查安全组是否开放了端口;
       4.如果${WP_HOST}是域名地址, 请确认是否在DNS服务器上配置了正确的解析;
       建议处理方案:
       1.如果是域名地址部署, 但域名尚未解析, 请解析之后直接访问后台测试或绑定客户端测试;
       2.如果是端口在安全组或防火墙未开放, 请开放后直接访问后台测试或绑定客户端测试(注意请勿修改服务器本机的iptables/firewalld防火墙配置);
       3.如果是填写了错误IP或域名部署, 请查阅'README安装指引.txt'里面的指引更换正确的地址重新部署;
       \033[0m"|tee -a ${platform_err_log}
    else
       echo -e "\n诊断测试结束,各接口响应如下:"
       echo -e "${check_seccuss_msg}"
    fi
    echo ""
    echo "=============================接口诊断完成============================="
}

initialize_mess () {
    echo ""
    echo "=============================脚本安装结束============================="
    echo ""
    setup_backup_cron
    {
        echo "感谢您安装 BeeWorks 产品。"
        echo "BeeWorks 已部署完成，请按照以下步骤开始使用："
        echo ""
        echo "一、访问管理后台"
        echo "管理后台地址：${url_prefix}://${WP_HOST}:${DASH_PORT}"
        echo "后台账号密码：注册激活时请自行设置。"
        echo "您可以访问管理后台进行注册激活、系统管理、用户管理、应用管理等操作。"
        echo ""
        echo "二、注册或添加用户"
        echo "您可以通过以下方式创建用户："
        echo "• 通过组织同步方式导入用户。"
        echo "• 管理员登录管理后台手动添加用户。"
        echo ""
        echo "三、下载安装客户端"
        echo "电脑端：请访问 https://sepro.beeworks.cn，支持下载 BeeWorks 全系客户端。"
        echo "手机端：打开手机应用市场（苹果AppStore / 安卓应用市场），搜索 \"BeeWorks\" 即可下载安装。"
        echo ""
        echo "四、绑定企业并登录"
        echo "首次登录 BeeWorks 客户端前，需要先绑定企业。"
        echo "绑定方式："
        echo "1. 打开 BeeWorks 客户端"
        echo "2. 输入访问地址：${url_prefix}://${WP_HOST}"
        echo "3. 完成企业绑定"
        echo "4. 使用已注册的账号登录 BeeWorks"
        echo "完成以上步骤后，即可开始使用 BeeWorks。"
        echo ""

        if [[ "${url_prefix}" == "https" ]]; then
            echo "您配置了 https 协议部署，请替换您域名的 SSL 证书到服务器目录 /home/workplus/nginx/certs。"
            echo "证书名字请保持和目录内原有证书的一致，请勿修改为其它名字，否则会导致服务启动异常。"
            echo "替换后请执行后面的命令重启相关服务：docker restart wp-server wp-http wp-dash wp-nginx"
        fi
    } | tee -a ${platform_msg_log}
    sync_success_deploy_result
}

sync_success_deploy_result() {
    # update_service 只更新已有部署中的单个服务，不执行首次部署成功回调。
    if [[ "${UPDATE_SERVICE_MODE}" == "true" ]]; then
        echo "服务更新模式，跳过成功部署结果回写" >> "${platform_msg_log}"
        return 0
    fi

    if [[ "${SUCCESS_CALLBACK_ENABLED}" != "true" ]]; then
        echo "成功回调已关闭，跳过部署结果回写" >> "${platform_msg_log}"
        return 0
    fi

    if [[ "${IS_FRESH_DEPLOY}" == "true" ]]; then
        sync_deploy_result "success" "WorkPlus-SE部署成功" "$(read_file_safe "${platform_msg_log}")--$(read_file_safe "${platform_pro_log}")--$(read_file_safe "${platform_err_log}")" "success"
    fi
}

setup_backup_cron() {
    local _mysql_backup_script="${WP_DIR}/mysql/backup/mysqlBackup_docker.sh"
    local _mongo_backup_script="${WP_DIR}/mongo/backup/mongoBackup_docker.sh"

    # 没有备份脚本则跳过
    if [[ ! -f "${_mysql_backup_script}" ]] && [[ ! -f "${_mongo_backup_script}" ]]; then
        echo "备份脚本不存在, 跳过定时任务配置" >>${platform_msg_log} 2>&1
        return
    fi

    echo -e "\n配置数据库定时备份任务（每天凌晨 04:00）" >>${platform_msg_log} 2>&1

    # 确保 crontab 可用（离线环境不尝试安装，直接跳过）
    if ! command -v crontab &>/dev/null; then
        if [[ "${check_network_code}" == "000" ]]; then
            echo "离线环境且未安装 crontab, 无法配置定时备份, 请手动安装 crontab 后执行备份脚本" | tee -a ${platform_err_log}
            return
        fi
        echo "crontab 命令不可用, 尝试在线安装..." >>${platform_msg_log} 2>&1
        if [[ "${DIST}" == CentOS* ]] || [[ "${DIST}" == "Red Hat"* ]] || [[ "${DIST}" == "Fedora"* ]] || \
           [[ "${DIST}" == "openEuler"* ]] || [[ "${DIST}" == "OpenCloudOS"* ]] || \
           [[ "${DIST}" == "TencentOS"* ]] || [[ "${DIST}" == "EulerOS"* ]] || \
           [[ "${DIST}" == "HCE"* ]]; then
            yum install -y cronie >>${platform_msg_log} 2>&1 || true
        elif [[ "${DIST}" == "Debian" ]] || [[ "${DIST}" == "Ubuntu"* ]]; then
            apt-get install -y -qq cron >>${platform_msg_log} 2>&1 || true
        elif [[ "${DIST}" == "SuSe" ]] || [[ "${DIST}" == "openSUSE"* ]]; then
            zypper install -y cronie >>${platform_msg_log} 2>&1 || true
        fi
    fi

    if ! command -v crontab &>/dev/null; then
        echo "crontab 不可用（安装失败或离线环境）, 跳过定时备份配置" | tee -a ${platform_err_log}
        return
    fi

    # 构建 crontab 条目
    local _existing
    _existing=$(crontab -l 2>/dev/null || true)
    local _mysql_cron="00 04 * * * /bin/bash ${_mysql_backup_script} >/dev/null 2>&1"
    local _mongo_cron="30 04 * * * /bin/bash ${_mongo_backup_script} >/dev/null 2>&1"
    local _need_update="false"

    # 追加 MySQL 备份任务（防重复）
    if [[ -f "${_mysql_backup_script}" ]] && ! echo "${_existing}" | grep -qF "${_mysql_backup_script}"; then
        _need_update="true"
        echo "${_mysql_cron}" >>/tmp/beeworks_cron
        echo "  + MySQL 备份: 每天 04:00 -> 日志 ${WP_DIR}/mysql/backup/backup_mysql.log" >>${platform_msg_log} 2>&1
    else
        echo "  - MySQL 备份任务已存在, 跳过" >>${platform_msg_log} 2>&1
    fi

    # 追加 Mongo 备份任务（防重复）
    if [[ -f "${_mongo_backup_script}" ]] && ! echo "${_existing}" | grep -qF "${_mongo_backup_script}"; then
        _need_update="true"
        echo "${_mongo_cron}" >>/tmp/beeworks_cron
        echo "  + Mongo 备份: 每天 04:30 -> 日志 ${WP_DIR}/mongo/backup/backup_mongo.log" >>${platform_msg_log} 2>&1
    else
        echo "  - Mongo 备份任务已存在, 跳过" >>${platform_msg_log} 2>&1
    fi

    if [[ "${_need_update}" == "true" ]]; then
        # 合并已有任务 + 新增任务
        if [[ -n "${_existing}" ]]; then
            echo "${_existing}" >>/tmp/beeworks_cron
        fi
        crontab /tmp/beeworks_cron
        echo "定时备份任务已写入 crontab" >>${platform_msg_log} 2>&1
    fi
    rm -f /tmp/beeworks_cron

    # 确保 cron 服务已启动并开机自启
    if command -v systemctl &>/dev/null; then
        systemctl enable crond 2>/dev/null || systemctl enable cron 2>/dev/null || true
        systemctl start crond 2>/dev/null || systemctl start cron 2>/dev/null || true
    elif command -v service &>/dev/null; then
        service crond start 2>/dev/null || service cron start 2>/dev/null || true
    fi
    echo "cron 服务已确保运行" >>${platform_msg_log} 2>&1
}

#initialize_report

run_install_service() {
    local service_container="$1"
    local service_function="$2"

    if [[ "${UPDATE_SERVICE_MODE}" == "true" ]] &&
       [[ "${UPDATE_SERVICE_CONTAINER}" != "${service_container}" ]] &&
       [[ "$(docker inspect -f '{{.State.Running}}' "${service_container}" 2>/dev/null || true)" == "true" ]]; then
        echo "${service_container} 已安装且正在运行，跳过启动、等待和状态检查" | tee -a ${platform_msg_log}
        return 0
    fi

    "${service_function}"
}

should_check_service_update() {
    local service_container="$1"
    [[ "${UPDATE_SERVICE_MODE}" != "true" || "${UPDATE_SERVICE_CONTAINER}" == "${service_container}" ]]
}

wait_and_check_service() {
    local wait_seconds="$1"
    local check_function="$2"

    if should_check_service_update "${3:-}"; then
        sleep "${wait_seconds}"
        "${check_function}"
    fi
}

# 更新服务前"真实下载"预检
# 说明: ping/curl/nc/状态码探测只能证明"可达", 无法覆盖"能连通但被限制下载"的网络
#       (企业网络常按域名/内容类型/流量大小限制下载, 拦截发生在数据传输阶段, 此时状态码探测仍会通过).
#       因此这里直接对目标镜像执行 docker pull —— 真实下载镜像层, 既验证下载能力, 也顺带完成镜像刷新.
#       拉取失败时在删除任何容器之前中断, 保证当前服务不中断.
pull_update_image () {
    local target_ref="$1"
    local retry_max=3
    local retry_interval=5
    local attempt
    local pull_rc

    for ((attempt = 1; attempt <= retry_max; attempt++)); do
        docker pull "${target_ref}" 2>&1 | tee -a ${platform_msg_log}
        pull_rc=${PIPESTATUS[0]}
        if [[ ${pull_rc} -eq 0 ]]; then
            echo "镜像拉取成功: ${target_ref}" >>${platform_msg_log} 2>&1
            return 0
        fi
        echo "[WARN] 镜像拉取失败, 第${attempt}/${retry_max}次: ${target_ref}" | tee -a ${platform_err_log}
        if [[ ${attempt} -lt ${retry_max} ]]; then
            echo "[WARN] ${retry_interval}秒后重试镜像拉取..." | tee -a ${platform_err_log}
            sleep "${retry_interval}"
        fi
    done
    return 1
}

update_service_resources() {
    local service_choice
    local selected_index
    local selected_service
    local selected_container
    local selected_image
    local selected_tag
    local target_ref
    local old_image_id
    local new_image_id
    local i

    local service_names=(
        "wp-http" "wp-dash" "wp-server" "wp-calendar" "wp-auditlog" "wp-nginx"
        "app-bpm" "app-tsq" "app-form" "app-html" "app-sync" "app-kaoqin" "app-document"
        "app-preview" "app-collabora"
        "db-mongo" "db-mysql" "db-redis" "db-minio"
        "meet-api" "kunlun-dapr" "bpm-intermediary"
    )
    local service_containers=(
        "${WP_HTTP_CONTAINER_NAME}" "${WP_DASH_CONTAINER_NAME}" "${WP_SERVER_CONTAINER_NAME}"
        "${WP_CALENDAR_CONTAINER_NAME}" "${WP_AUDITLOG_CONTAINER_NAME}" "${NGINX_CONTAINER_NAME}"
        "${APP_BPM_CONTAINER_NAME}" "${APP_TSQ_CONTAINER_NAME}" "${APP_FORM_CONTAINER_NAME}"
        "${APP_HTML_CONTAINER_NAME}" "${APP_SYNC_CONTAINER_NAME}" "${APP_KAOQIN_CONTAINER_NAME}"
        "${DOCUMENT_CONTAINER_NAME}"
        "${APP_PREVIEW_CONTAINER_NAME}" "${APP_COLLABORA_CONTAINER_NAME}"
        "${MONGO_CONTAINER_NAME}" "${MYSQL_CONTAINER_NAME}" "${REDIS_CONTAINER_NAME}" "${MINIO_CONTAINER_NAME}"
        "${MEETAPI_CONTAINER_NAME}" "${KUNLUN_DAPR_CONTAINER_NAME}" "${BPM_INTERMEDIARY_CONTAINER_NAME}"
    )
    local service_images=(
        "${WP_HTTP_IMAGE_NAME}" "${WP_DASH_IMAGE_NAME}" "${WP_SERVER_IMAGE_NAME}"
        "${WP_CALENDAR_IMAGE_NAME}" "${WP_AUDITLOG_IMAGE_NAME}" "${NGINX_IMAGE_NAME}"
        "${APP_BPM_IMAGE_NAME}" "${APP_TSQ_IMAGE_NAME}" "${APP_FORM_IMAGE_NAME}"
        "${APP_HTML_IMAGE_NAME}" "${APP_SYNC_IMAGE_NAME}" "${APP_KAOQIN_IMAGE_NAME}"
        "${DOCUMENT_IMAGE_NAME}"
        "${APP_PREVIEW_IMAGE_NAME}" "${APP_COLLABORA_IMAGE_NAME}"
        "${MONGO_IMAGE_NAME}" "${MYSQL_IMAGE_NAME}" "${REDIS_IMAGE_NAME}" "${MINIO_IMAGE_NAME}"
        "${MEETAPI_IMAGE_NAME}" "${KUNLUN_DAPR_IMAGE_NAME}" "${BPM_INTERMEDIARY_IMAGE_NAME}"
    )
    # service_tags 与 service_names/service_images 按下标一一对应
    local service_tags=(
        "${WP_VERSION}" "${WP_VERSION}" "${WP_VERSION}"
        "${WP_VERSION}" "${WP_VERSION}" "${NGINX_IMAGE_TAG}"
        "${APP_BPM_IMAGE_TAG}" "${APP_TSQ_IMAGE_TAG}" "${APP_FORM_IMAGE_TAG}"
        "${APP_HTML_IMAGE_TAG}" "${APP_SYNC_IMAGE_TAG}" "${APP_KAOQIN_IMAGE_TAG}"
        "${DOCUMENT_IMAGE_TAG}"
        "${APP_PREVIEW_IMAGE_TAG}" "${APP_COLLABORA_IMAGE_TAG}"
        "${MONGO_IMAGE_TAG}" "${MYSQL_IMAGE_TAG}" "${REDIS_IMAGE_TAG}" "${MINIO_IMAGE_TAG}"
        "${MEETAPI_IMAGE_TAG}" "${KUNLUN_VERSION}" "${BPM_INTERMEDIARY_IMAGE_TAG}"
    )

    if ! command -v docker >/dev/null 2>&1; then
        echo "未检测到docker命令, 无法执行服务更新"
        exit 1
    fi

    echo ""
    echo "请选择需要更新的容器服务："
    for i in "${!service_names[@]}"; do
        printf "%2d. %s\n" "$((i + 1))" "${service_names[$i]}"
    done
    echo "00. 取消更新"
    while true; do
        read -e -r -p "请输入服务编号: " service_choice
        if [[ "$service_choice" == "00" ]]; then
            echo "已取消服务更新"
            exit 0
        fi
        if [[ "$service_choice" =~ ^[0-9]+$ ]] && (( service_choice >= 1 && service_choice <= ${#service_names[@]} )); then
            selected_index=$((service_choice - 1))
            break
        fi
        echo "输入无效，请输入 1-${#service_names[@]} 之间的服务编号，或输入 0 取消"
    done

    selected_service="${service_names[$selected_index]}"
    selected_container="${service_containers[$selected_index]}"
    selected_image="${service_images[$selected_index]}"
    selected_tag="${service_tags[$selected_index]}"
    UPDATE_SERVICE_CONTAINER="${selected_container}"

    target_ref="${selected_image}:${selected_tag}"

    echo "即将更新服务: ${selected_service}"
    echo "目标镜像: ${target_ref}"

    # 记录旧镜像ID, 用于拉取到新镜像后清理被替换的旧镜像(避免遗留 dangling 镜像)
    old_image_id=$(docker image inspect -f '{{.Id}}' "${target_ref}" 2>/dev/null || true)

    # 先真实拉取目标镜像: 同时完成"下载能力校验"与"镜像刷新".
    # 若因离线或网络限制下载而失败, 则在删除旧容器之前中断, 当前服务保持不变(不产生服务中断).
    echo ""
    echo "正在拉取目标镜像(校验下载能力), 请稍候..."
    if ! pull_update_image "${target_ref}"; then
        echo ""
        echo "[ERROR] 服务器无法联网下载镜像资源(离线或网络限制下载)，不支持在线更新。" | tee -a ${platform_err_log}
        echo "[ERROR] 为避免先删除容器和镜像后无法重新拉取镜像导致服务中断，已终止本次更新操作，当前服务保持不变。" | tee -a ${platform_err_log}
        echo "[ERROR] 请确认服务器可正常下载镜像(镜像仓库 swr.cn-south-1.myhuaweicloud.com)后重试。" | tee -a ${platform_err_log}
        exit 1
    fi

    # 镜像已就绪, 再删除旧容器; 不再删除镜像, 安装流程会复用刚拉取的镜像
    echo "删除容器: ${selected_container}"
    if docker container inspect "${selected_container}" >/dev/null 2>&1; then
        docker rm -f "${selected_container}" || {
            echo "错误: 删除容器失败: ${selected_container}"
            exit 1
        }
    else
        echo "容器不存在，继续执行安装流程"
    fi

    # 若本次拉取已把 tag 指向新镜像, 清理被替换的旧镜像, 避免占用磁盘
    if [[ -n "${old_image_id}" ]]; then
        new_image_id=$(docker image inspect -f '{{.Id}}' "${target_ref}" 2>/dev/null || true)
        if [[ -n "${new_image_id}" && "${new_image_id}" != "${old_image_id}" ]]; then
            echo "清理被替换的旧镜像: ${old_image_id}"
            docker image rm "${old_image_id}" >/dev/null 2>&1 || true
        fi
    fi

    echo "服务 ${selected_service} 的镜像已就绪、容器已清理，开始执行安装流程"
}

wait_core_service_ready() {
    local service_container="${UPDATE_SERVICE_CONTAINER}"
    local health_port=""
    local max_attempts=60
    local check_interval=5
    local attempt=1
    local health_response

    [[ "${UPDATE_SERVICE_MODE}" == "true" ]] || return 0

    case "${service_container}" in
        "${WP_SERVER_CONTAINER_NAME}")
            health_port=9924
        ;;
        "${WP_HTTP_CONTAINER_NAME}"|"${WP_DASH_CONTAINER_NAME}")
            health_port=9000
        ;;
        *)
            return 0
        ;;
    esac

    echo "${service_container} 更新完成，等待应用启动完成后再进行接口诊断（最多等待 $((max_attempts * check_interval)) 秒）" | tee -a "${platform_msg_log}"

    while (( attempt <= max_attempts )); do
        if [[ "$(docker inspect -f '{{.State.Running}}' "${service_container}" 2>/dev/null || true)" != "true" ]]; then
            health_response="容器未处于运行状态"
        else
            health_response=$(docker exec "${service_container}" sh -c "curl -sS --connect-timeout 3 --max-time 5 http://127.0.0.1:${health_port}/_health" 2>&1 || true)
        fi

        if echo "${health_response}" | grep -q "Service healthy"; then
            echo "${service_container} 应用已启动完成，开始接口诊断" | tee -a "${platform_msg_log}"
            return 0
        fi

        if (( attempt < max_attempts )); then
            echo "[${attempt}/${max_attempts}] ${service_container} 尚未启动完成，继续等待 ${check_interval} 秒" >> "${platform_msg_log}"
            sleep "${check_interval}"
        fi
        attempt=$((attempt + 1))
    done

    echo "警告: ${service_container} 等待 ${max_attempts} 次后仍未通过应用健康检查，将继续执行接口诊断" | tee -a "${platform_err_log}"
    echo "最后一次健康检查响应: ${health_response}" >> "${platform_err_log}"
}

is_core_service_running_over_day() {
    local service_container
    local container_state
    local started_at
    local started_epoch
    local current_epoch
    local running_seconds
    local core_service_containers=("db-mysql" "db-mongo" "db-redis" "db-minio" "kunlun-dapr")

    current_epoch=$(date +%s)
    for service_container in "${core_service_containers[@]}"; do
        container_state=$(docker inspect --format '{{.State.Status}}|{{.State.StartedAt}}' "${service_container}" 2>/dev/null) || continue
        [[ "${container_state%%|*}" == "running" ]] || continue

        started_at="${container_state#*|}"
        started_epoch=$(date -d "${started_at}" +%s 2>/dev/null) || continue
        running_seconds=$((current_epoch - started_epoch))
        if (( running_seconds > 86400 )); then
            IS_FRESH_DEPLOY="false"
            echo "${service_container} 已正常运行超过一天，判定为非首次部署，跳过成功部署结果回写" >> "${platform_msg_log}" 2>&1
            return 0
        fi
    done

    return 1
}

install () {
    if docker ps -aq --format '{{.Names}}' 2>/dev/null | grep -Eq '^(wp-server|wp-http|wp-dash|wp-calendar|wp-auditlog|kunlun-dapr|db-fdfs|db-mongo|db-mysql|db-redis|app-bpm|app-form|app-tsq|app-html|app-kaoqin|app-sync|app-document|meet-api|wp-nginx|db-minio|bpm-intermediary)$'; then
        IS_FRESH_DEPLOY="false"
    else
        IS_FRESH_DEPLOY="true"
    fi

    # 未传第二参数时，用核心基础服务的长期运行状态识别是否为首次部署。
    # 任一核心服务已正常运行超过一天，即使其他容器刚被创建，也不再触发成功回调。
    if [[ -z "${SECOND_ARGS}" ]]; then
        is_core_service_running_over_day || true
    fi

    echo "部署类型: ${IS_FRESH_DEPLOY}" >> ${platform_msg_log} 2>&1

    echo -e "
-------------------------------------------------------------

    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@@@%((((((((#&@@@((#((#@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@%(((((((((((((%@*((((@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@%(((/,/(((((((((@@@*#@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@#(((@@@((((((((((@@((@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@(((((((((((((((((((((@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@(((((((((((((((((((@@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@@@(((((((((((((((*@@@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
    @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
                           __           __
     .--.--.--.-----.----.|  |--.-----.|  |.--.--.-----.
     |  |  |  |  _  |   _||    <|  _  ||  ||  |  |__ --|
     |________|_____|__|  |__|__|   __||__||_____|_____|
                                |__|

"
    echo "Copyright (c) 2015, 2026, Forever High Tech and/or its affiliates. All rights reserved."
    echo ""
    echo -e "\033[1;37mThe script is running, This may take a few minutes ...\033[0m";
    echo ""

    root_checking
    check_hardware
    check_os
    if [[ "${MACH}" == "x86_64" ]]; then
    check_kernel
    fi
#   check_mysql
#   check_mongo
#   check_redis
#   check_minio
    check_im_ssl
    check_im_type
    check_prompt
    check_ipv4
    check_network
    update_source
    install_jq
    install_curl
    install_iptables
    install_tar
    update_time
    define_ports
    check_runc
    install_docker
    check_docker_status
    import_images
    check_ports
    init_directories
    init_db_files
    init_network
    get_driver
    run_install_service "${MYSQL_CONTAINER_NAME}" install_mysql
    run_install_service "${MONGO_CONTAINER_NAME}" install_mongo
    run_install_service "${REDIS_CONTAINER_NAME}" install_redis
    if [[ "${EXT_OVERLAYFS_DRIVER}" == "fastdfs" ]]; then
        run_install_service "${FASTDFS_CONTAINER_NAME}" install_fastdfs
    fi
    if [[ "${EXT_OVERLAYFS_DRIVER}" == "s3" ]]; then
        run_install_service "${MINIO_CONTAINER_NAME}" install_minio
    fi
    update_wphost
    reset_domain
    run_install_service "${KUNLUN_DAPR_CONTAINER_NAME}" install_dapr
    run_install_service "${WP_SERVER_CONTAINER_NAME}" install_server
    run_install_service "${WP_HTTP_CONTAINER_NAME}" install_http
    run_install_service "${WP_DASH_CONTAINER_NAME}" install_dash
    run_install_service "${WP_CALENDAR_CONTAINER_NAME}" install_calendar
    run_install_service "${WP_AUDITLOG_CONTAINER_NAME}" install_auditlog
    run_install_service "${APP_FORM_CONTAINER_NAME}" install_app_form
    run_install_service "${APP_TSQ_CONTAINER_NAME}" install_app_tsq
    run_install_service "${APP_KAOQIN_CONTAINER_NAME}" install_app_kaoqin
    run_install_service "${APP_BPM_CONTAINER_NAME}" install_app_bpm
    run_install_service "${BPM_INTERMEDIARY_CONTAINER_NAME}" install_bpm_intermediary
    run_install_service "${MEETAPI_CONTAINER_NAME}" install_meet_api
    run_install_service "${APP_SYNC_CONTAINER_NAME}" install_app_sync
    run_install_service "${APP_PREVIEW_CONTAINER_NAME}" install_app_preview
    run_install_service "${APP_COLLABORA_CONTAINER_NAME}" install_app_collabora
    run_install_service "${APP_HTML_CONTAINER_NAME}" install_app_html
    run_install_service "${DOCUMENT_CONTAINER_NAME}" install_app_document
    run_install_service "${NGINX_CONTAINER_NAME}" install_nginx
    if [[ "${UPDATE_SERVICE_MODE}" != "true" ]]; then
        check_mysql_table
        check_server_status
        check_http_status
        check_dash_status
    fi
}

if [[ "${UPDATE_SERVICE_MODE}" == "true" ]]; then
    update_service_resources
fi
install
wait_core_service_ready
check_summary
initialize_mess
