#!/bin/bash

# shellcheck disable=SC2164
# bin目录的绝对路径，eg: /kingdee/cosmic/mdd/olapserver/bin
binPath=$(cd "$(dirname "$0")"; pwd -P)
# olap 服务所在路径，eg: /kingdee/cosmic/mdd/olapserver
olapServerPath=$binPath/..
# command.pid 所在路径，eg: /kingdee/cosmic/mdd/olapserver/bin/command.pid
mddPidPath=$binPath/command.pid
# 历史中所有服务启动过程中所生产的日志，eg: /kingdee/cosmic/mdd/olapserver/bin/server.log
serverLogPath=$binPath/server.log
# 本次服务启动过程中所生产的日志，eg: /kingdee/cosmic/mdd/olapserver/bin/currentServer.log
currentServerStartLogPath=$binPath/currentServerStart.log
currentServerStopLogPath=$binPath/currentServerStop.log
# 当前执行版本号，eg: 9.7.12
version=$(cat "$binPath"/version)
divisionLine="=============================================================================================="
cd "$binPath"/..

start() {
    echo "$divisionLine" > "$currentServerStartLogPath" # 覆盖写入
    currentPid=$(getCurrentPid)
    # 将启动过程中的所有日志信息（不管是成功还是失败）都打印到控制台，随着启动脚本结束，tail进程自动结束
    tail --pid=$$ -n 1 -f "$currentServerStartLogPath" &
    if [[ "$currentPid" = "" ]]; then # 如果需要在（i386,X86,x86_64,amd64）以外的cpu机器上运行(比如arm，申威，龙芯)，需要在java命令加上这个参数: -DEnableMddOtherCpu=true
        echo "Starting..., the current time is: $(date +"%Y-%m-%d %H:%M:%S")" >> "$currentServerStartLogPath"
        echo "Setting up the system parameters required for the MDD service, please wait..." >> "$currentServerStartLogPath"
        setEnv
        echo "System parameters have been set up." >> "$currentServerStartLogPath"
        echo "MDD service is starting, please wait..." >> "$currentServerStartLogPath"
        nohup java -Duser.timezone="GMT+8" -classpath "$olapServerPath/$version/lib/*:." kd.bos.olap.server.OlapWebServerMain >> "$currentServerStartLogPath" 2>&1 & echo $! > "$mddPidPath"
        # 及时将日志追加写入，随着启动脚本结束，tail进程自动结束
        tail --pid=$$ -n 200 -f "$currentServerStartLogPath" >> "$serverLogPath" 2>&1 &
        # 等待启动程序执行完毕
        if waitUntilStartFinish; then
            # 启动成功
            startSuccess
        else
            startFailed "An error occurred."
        fi
    else
        # 使用红色字体
        echo -e "\033[31mMDD service has already started, please do not start it again. MDD PID: '$currentPid'. \033[0m" >> "$currentServerStartLogPath"
        exit 1
    fi
}

stop() {
    echo "$divisionLine" > "$currentServerStopLogPath"
    # 将停止过程中的所有日志信息（不管是成功还是失败）都打印到控制台，随着脚本结束，tail进程自动结束
    tail --pid=$$ -n 1 -f "$currentServerStopLogPath" &
    tail --pid=$$ -n 1 -f "$currentServerStopLogPath" >> "$serverLogPath" 2>&1 &
    echo "Stopping..., the current time is: $(date +"%Y-%m-%d %H:%M:%S")" >> "$currentServerStopLogPath"
    currentPid=$(getCurrentPid)
    tmpPid=$(ps -ef|grep java|grep OlapWebServerMain|grep "$binPath"| grep -v grep| tr -s ' '| cut -d ' ' -f 2)
    if [[ "$currentPid" != "$tmpPid" ]]; then
        for i in $tmpPid ;do
            echo "$i will be stop." >> "$currentServerStopLogPath"
            kill -15 "$i"
            waitUntilStop "$i"
        done
        currentPid=""
    fi

    if [[ "$currentPid" != "" ]]; then
    	echo "$currentPid will be stop." >> "$currentServerStopLogPath"
        kill -15 "$currentPid"
        waitUntilStop "$currentPid"
    fi

    # 使用绿色字体
    echo -e "\033[32mMDD service stopped successfully. \033[0m" >> "$currentServerStopLogPath"
    echo "$divisionLine" >> "$currentServerStopLogPath"

    sleep 3 # 确保 stop 的 tail 进程执行完毕
}

status() {
    currentPid=$(getCurrentPid)
    if [[ "$currentPid" = "" ]]; then
        echo "The MDD service is not running."
    else
        echo "MDD service is running."
    fi
    exit 0
}

restart() {
    stop
    start
}

# 获取当前 MDD 的 pid
getCurrentPid() {
    if [[ -e $mddPidPath ]];then
        currentPid=$(cat "$mddPidPath")
        # shellcheck disable=SC2009
        tmpPid=$(ps --no-headers -fp "$currentPid"|grep -c java)
		if [[ $tmpPid -ne 1 ]];then
		   currentPid=""
		fi
    else
        currentPid=""
	fi
    echo "$currentPid"
}

# 等待MDD停止
waitUntilStop() {
    needPrint=true
    while true
    do
        exist_flg=$(ps --no-headers -fp "$1" |wc -l)
        if [[ $exist_flg -eq 0 ]]; then
            rm -rf "$mddPidPath"
            break
        else
            if  $needPrint ; then
                echo "Please wait for the MDD service to stop..." >> "$currentServerStopLogPath"
                needPrint=false
            fi
	        sleep 1
        fi
    done
}

# 等待 MDD 启动程序执行完毕，直到启动成功或者启动失败
waitUntilStartFinish() {
    while true; do
      # 读取文件最后一行
      LAST_LINE=$(tail -n 1 "$currentServerStartLogPath")
      # 检查最后一行是否以"========="开头
      if [[ "$LAST_LINE" == "========="* ]]; then
          # 搜索是否启动失败
          if grep -q "Mdd service startup failed." "$currentServerStartLogPath"; then
              return 1
          else
              return 0
          fi
      else
          # 等待一段时间后再次检查，这里设置为每隔1秒检查一次
          sleep 1
      fi
    done
}

# 启动成功的处理函数
startSuccess() {
    # 进程ID
    currentPid=$(getCurrentPid)
    # 使用绿色字体
    echo -e "\033[32mMDD service started successfully. MDD PID: '$currentPid' \033[0m" >> "$currentServerStartLogPath"
    exit 0
}

# 警告函数
startWarn() {
    # 获取错误信息
    local warnMsg="$1"

    # 使用黄色字体
    echo -e "\033[33mWarning: ${warnMsg} \033[0m" >&2
}

# 启动失败的处理函数
startFailed() {
    # 获取错误信息
    local failMsg="$1"

    # 使用红色字体
    echo -e "\033[31mMDD service failed to start. ${failMsg} \033[0m" >> "$currentServerStartLogPath"
    rm -rf "$mddPidPath"
    exit 1
}

# 设置系统参数，需要 root 权限，如果没有 root 权限，则抛出一个警告
setEnv() {
    setOpenFileDescriptorsLimit
    setVMMaxMapCount
    setVMOverCommitMemory
    # 使 sysctl 配置修改生效
    sysctl -p > /dev/null 2>&1
}

# 设置每个进程可以打开的最大文件数目
setOpenFileDescriptorsLimit() {
    # 获取当前的硬限制值
    limit_hard_open_file=$(ulimit -Hn)

    # 如果小于 1048576，设置为 1048576
    # 必须要先设置硬限制，然后再设置软限制（如果硬限制小于软限制，会报错）
    if [[ "$limit_hard_open_file" -lt 1048576 ]]; then
        ulimit -Hn 1048576 > /dev/null 2>&1
        ulimit -Sn 1048576 > /dev/null 2>&1
    else
        limit_soft_open_file=$(ulimit -Sn)
        if [[ "$limit_soft_open_file" -lt 1048576 ]]; then
            ulimit -Sn 1048576 > /dev/null 2>&1
        fi
    fi

    # 检查 ulimit -n 是否设置成功
    if [[ $(ulimit -Hn) -lt 1048576 ]]; then
        startWarn "Failed to set system parameter 'ulimit -Hn'. Please execute with root privileges. Or manually execute the command: 'ulimit -Hn 1048576'"
    fi
    if [[ $(ulimit -Sn) -lt 1048576 ]]; then
        startWarn "Failed to set system parameter 'ulimit -Sn'. Please execute with root privileges. Or manually execute the command: 'ulimit -Sn 1048576'"
    fi
}

# 进程能够拥有的最大内存映射区域数量
setVMMaxMapCount() {
    value=$(sysctl vm.max_map_count | awk '{print $3}')
    if [[ "$value" -lt 1048576 ]]; then
        sysctl -w vm.max_map_count=1048576 > /dev/null 2>&1
    fi

    # 检查是否设置成功
    if [[ $(sysctl vm.max_map_count | awk '{print $3}') -lt 1048576 ]]; then
        startWarn "Failed to set system parameter 'vm.max_map_count'. Please execute with root privileges. Or manually execute the command: 'sysctl -w vm.max_map_count=1048576'"
    fi
}

# 内存分配策略修改
setVMOverCommitMemory() {
    value=$(sysctl vm.overcommit_memory | awk '{print $3}')
    if [[ "$value" -ne 0 ]]; then
        sysctl -w vm.overcommit_memory=0 > /dev/null 2>&1
    fi

    # 检查是否设置成功
    if [[ $(sysctl vm.overcommit_memory | awk '{print $3}') -ne 0 ]]; then
        startWarn "Failed to set system parameter 'vm.overcommit_memory'. Please execute with root privileges. Or manually execute the command: 'sysctl -w vm.overcommit_memory=0'"
    fi
}

case $1 in
start)
       start
       ;;
stop)
       stop
       ;;
restart)
        restart
        ;;
status)
       status
       ;;
*)
        echo "Usage: $0  start | stop | restart | status ."
        ;;
esac