# linux script server control logic functions encapsulation.
# Longwei Lai
###################################################################

source "${____FWK_SCRIPT_PATH}/lnx_fwk_path.sh"
source "${____FWK_SCRIPT_PATH}/lnx_fwk_server.sh"
source "${____LOGIC_SCRIPT_PATH}/lnx_logic_defs.sh"
source "${____LOGIC_SCRIPT_PATH}/lnx_logic_serverhttp.sh"
source "${____LOGIC_SCRIPT_PATH}/lnx_logic_serversql.sh"
source "${____LOGIC_SCRIPT_PATH}/lnx_logic_serverconf.sh"
source "${____LOGIC_SCRIPT_PATH}/lnx_logic_serverstatus.sh"

function server_ctrl_cmd_adapt()
{
    local args=($@)

    local cmd=${args[0]}
    local cmd_type=${cmd%%_*}
    local server_type=${cmd#*_}
    local ctrl_args=${args[@]:1}

    if [ "${server_type}" = "status" -o "${server_type}" = "st" -o\
         "${server_type}" = "logic_status" -o "${server_type}" = "logic_st" ]; then
        local tmp=${cmd_type}
        cmd_type=${server_type}
        server_type=${tmp}
    fi

    case  "${cmd_type}" in
        start)
            server_ctrl_start ${server_type} ${ctrl_args}
            ;;
        stop)
            server_ctrl_stop ${server_type} ${ctrl_args}
            ;;
        safestop)
            server_ctrl_safestop ${server_type} ${ctrl_args}
            ;;
        restart)
            server_ctrl_restart ${server_type} ${ctrl_args}
            ;;
        status)
            server_ctrl_status ${server_type} ${ctrl_args}
            ;;
        logic_status)
            server_ctrl_logic_status ${server_type} ${ctrl_args}
            ;;
        set)
            server_ctrl_set ${server_type} ${ctrl_args}
            ;;

        *)
            list_help
            return 0
            ;;
    esac
}

function server_ctrl_start()
{
    local args=($@)

    local server_type=${args[0]}
    local start_args=${args[@]:1}

    case "${server_type}" in
        devilserver)
            start_gameserver ${start_args}
            ;;
        ruinsserver)
            start_gameserver ${start_args}
            ;;
        gameserver)
            start_gameserver ${start_args}
            ;;
        pyramidserver)
            start_gameserver ${start_args}
            ;;
        legendserver)
            start_gameserver ${start_args}
            ;;
        cloudserver)
            start_gameserver ${start_args}
            ;;
        loginserver)
            start_loginserver ${start_args}
            ;;
        globalserver)
            start_globalserver ${start_args}
            ;;
        webserver)
            start_webserver ${start_args}
            ;;
        *)
            log_err "unknown server[${server_type}], start server failed"
            return 1
            ;;
    esac
}

function server_ctrl_stop()
{
    local args=($@)

    local server_type=${args[0]}
    local stop_args=${args[@]:1}

    case "${server_type}" in
        devilserver)
            stop_gameserver ${stop_args}
            ;;
        ruinsserver)
            stop_gameserver ${stop_args}
            ;;
        gameserver)
            stop_gameserver ${stop_args}
            ;;
        pyramidserver)
            stop_gameserver ${stop_args}
            ;;
        legendserver)
            stop_gameserver ${stop_args}
            ;;
        cloudserver)
            stop_gameserver ${stop_args}
            ;;
        loginserver)
            stop_loginserver ${stop_args}   
            ;;
        globalserver)
            stop_globalserver ${stop_args}
            ;;
        webserver)
            stop_webserver ${stop_args}
            ;;
        *)
            log_err "unknown server[${server_type}], stop server failed"
            return 1
            ;;
    esac
}

function server_ctrl_safestop()
{
    local args=($@)

    local server_type=${args[0]}
    local stop_args=${args[@]:1}

    case "${server_type}" in
        devilserver)
            safestop_gameserver ${stop_args}
            ;;
        ruinsserver)
            safestop_gameserver ${stop_args}
            ;;
        gameserver)
            safestop_gameserver ${stop_args}
            ;;
        pyramidserver)
            safestop_gameserver ${stop_args}
            ;;
        legendserver)
            safestop_gameserver ${stop_args}
            ;;
        cloudserver)
            safestop_gameserver ${stop_args}
            ;;
        loginserver)
            safestop_loginserver ${stop_args}
            ;;
        globalserver)
            safestop_globalserver ${stop_args}
            ;;
        webserver)
            safestop_webserver ${stop_args}
            ;;
        *)
            log_err "unknown server[${server_type}], safestop server failed"
            return 1
            ;;
    esac
}

function server_ctrl_restart()
{
    local args=($@)

    local server_type=${args[0]}
    local restart_args=${args[@]:1}

    case "${server_type}" in
        devilserver)
            restart_gameserver ${restart_args}
            ;;
        ruinsserver)
            restart_gameserver ${restart_args}
            ;;
        gameserver)
            restart_gameserver ${restart_args}
            ;;
        pyramidserver)
            restart_gameserver ${restart_args}
            ;;
        legendserver)
            restart_gameserver ${restart_args}
            ;;
        cloudserver)
            restart_gameserver ${restart_args}
            ;;
        loginserver)
            restart_loginserver ${restart_args}
            ;;
        globalserver)
            restart_globalserver ${restart_args}
            ;;
        webserver)
            restart_webserver ${restart_args}
            ;;
        *)
            log_err "unknown server[${server_type}], restart server failed"
            return 1
            ;;
    esac
}

function server_ctrl_status()
{
    local args=($@)

    local server_type=${args[0]}
    local list_args=${args[@]:1}

    case "${server_type}" in
        devilserver)
            list_gameserver_status ${list_args}
            ;;
        ruinsserver)
            list_gameserver_status ${list_args}
            ;;
        gameserver)
            list_gameserver_status ${list_args}
            ;;
        pyramidserver)
            list_gameserver_status ${list_args}
            ;;
        legendserver)
            list_gameserver_status ${list_args}
            ;;
        cloudserver)
            list_gameserver_status ${list_args}
            ;;
        loginserver)
            list_loginserver_status ${list_args}
            ;;
        globalserver)
            list_globalserver_status ${list_args}
            ;;
        webserver)
            list_webserver_status ${list_args}
            ;;
        *)
            log_err "unknown server[${server_type}], restart server failed"
            return 1
            ;;
    esac
}

function server_ctrl_logic_status()
{
    local args=($@)

    local server_type=${args[0]}
    local list_args=${args[@]:1}

    case "${server_type}" in
        gameserver)
            echo "gameserver logic status:"
            echo "`get_gameserver_logic_status`"
            ;;
        pyramidserver)
            echo "pyramidserver logic status:"
            echo "`get_gameserver_logic_status`"
            ;;
        legendserver)
            echo "legendserver logic status:"
            echo "`get_gameserver_logic_status`"
            ;;
        devilserver)
            echo "devilserver logic status:"
            echo "`get_gameserver_logic_status`"
            ;;
        cloudserver)
            echo "cloudserver logic status:"
            echo "`get_gameserver_logic_status`"
            ;;
        *)
            echo "${server_type} logic status: Unknown"
            ;;
    esac
}

function server_ctrl_set()
{
    local args=($@)

    local server_type_and_set_type=${args[0]}
    local list_args=${args[@]:1}

    case "${server_type_and_set_type}" in
        gameserver_logic_status|pyramidserver_logic_status|legendserver_logic_status|devilserver_logic_status)
            set_gameserver_logic_status ${list_args}
            ;;
        *)
            log_info "for now, not support <${server_type_and_set_type}> command!"
            ;;
    esac
}

function start_gameserver()
{
    echo "game start config";
    check_app_type "gs"

    local args=$@
    local server_entry="${FRAMEWORK_PATH}/skynet/skynet"
    local start_file="${SVR_PATH}/${____START_FILE_GAME}"
    local result_file="${SVR_PATH}/${____START_RESULT_FILE_GAME}"

    start_server_and_wait "${____LOGIC_GAME}" "${server_entry}" "${____APP_START_CONF_NAME}" "${start_file}" "${result_file}" ${args}
}

function stop_gameserver()
{
    local args=$@
    stop_server "${____LOGIC_GAME}" ${args}

    local start_file="${SVR_PATH}/${____START_FILE_GAME}"
    remove_server_start_file "${start_file}"
}

function restart_gameserver()
{
    local args=$@
    stop_gameserver ${args}
    echo "Sleep 5 second..."
    sleep 5

    start_gameserver ${args}
}

function list_gameserver_status()
{
    local args=$@

    list_server_status "${____LOGIC_GAME}" ${args}
}

function start_loginserver()
{
    echo "login start config";
    check_app_type "ls"

    local args=$@
    local server_entry="${FRAMEWORK_PATH}/skynet/skynet"
    local start_file="${SVR_PATH}/${____START_FILE_LOGIN}"
    local result_file="${SVR_PATH}/${____START_RESULT_FILE_LOGIN}"

    start_server_and_wait "${____LOGIC_LOGIN}" "${server_entry}" "${____APP_START_CONF_NAME}" "${start_file}" "${result_file}" ${args}
}

function stop_loginserver()
{
    local args=$@
    stop_server "${____LOGIC_LOGIN}" ${args}

    local start_file="${SVR_PATH}/${____START_FILE_LOGIN}"
    remove_server_start_file "${start_file}"
}

function restart_loginserver()
{
    local args=$@

    stop_loginserver $args
    echo "Sleep 5 second..."
    sleep 5

    start_loginserver $args
}

function list_loginserver_status()
{
    local args=$@
    list_server_status "${____LOGIC_LOGIN}" ${args}
}

function auto_update_db()
{
    local arg_env=`cat ${____APP_START_CONF_NAME} | grep app_env | awk -F\" '{print $2}'`
    if [[ ${arg_env} == "dev" ]] || [[ ${arg_env} == "sit" ]]; then
        local dbconf_name=dbconf.lua
        sh ${MISC_SCRIPTS_PATH}/lnx_logic_updatedb.sh ${dbconf_name}
    fi
}

function start_globalserver()
{
    echo "global start config";
    check_app_type "ms"

    auto_update_db

    local args=$@
    local server_entry="${FRAMEWORK_PATH}/skynet/skynet"
    local start_file="${SVR_PATH}/${____START_FILE_GLOBAL}"
    local result_file="${SVR_PATH}/${____START_RESULT_FILE_GLOBAL}"
    start_server_and_wait "${____LOGIC_GLOBAL}" "${server_entry}" "${____APP_START_CONF_NAME}" "${start_file}" "${result_file}" ${args}
}

function stop_globalserver()
{
    local args=$@
    stop_server "${____LOGIC_GLOBAL}" ${args}

    local start_file="${SVR_PATH}/${____START_FILE_GLOBAL}"
    remove_server_start_file "${start_file}"
}

function restart_globalserver()
{
    local args=$@

    stop_globalserver $args
    echo "Sleep 5 second..."
    sleep 5

    start_globalserver $args
}

function list_globalserver_status()
{
    local args=$@
    list_server_status "${____LOGIC_GLOBAL}" ${args}
}

function check_app_type() {
    cat ${____APP_START_CONF_NAME};

    local tar_type=${1}
    local app_type=`cat ${____APP_START_CONF_NAME} | grep app_type | awk -F\" '{print $2}'`
    if [[ "${app_type}" != "${tar_type}" ]]; then
        echo "app_type[${app_type}] error"
        exit 1
    fi
}

function start_webserver()
{
    echo "web start config";
    check_app_type "ws"

    local args=$@
    local server_entry="${FRAMEWORK_PATH}/skynet/skynet"
    local start_file="${SVR_PATH}/${____START_FILE_WEB}"
    local result_file="${SVR_PATH}/${____START_RESULT_FILE_WEB}"

    start_server_and_wait "${____LOGIC_WEB}" "${server_entry}" "${____APP_START_CONF_NAME}" "${start_file}" "${result_file}" ${args}
}

function stop_webserver()
{
    local args=$@
    stop_server "${____LOGIC_WEB}" ${args}

    local start_file="${SVR_PATH}/${____START_FILE_WEB}"
    remove_server_start_file "${start_file}"
}

function restart_webserver()
{
    local args=$@

    stop_webserver $args
    echo "Sleep 5 second..."
    sleep 5

    start_webserver $args
}

function list_webserver_status()
{
    local args=$@
    list_server_status "${____LOGIC_WEB}" ${args}
}

function start_server_and_wait()
{
    local server_name="$1"
    local server_entry="$2"
    local server_config_file="$3"
    local start_file="$4"
    local result_file="$5"

    # parse arguments and get server start args
    local args=($@)
    local start_args="${args[@]:5}"

    # remove start result file first
    \rm -rf "${result_file}"

    \rm -rf "${start_file}"

    # start loginserver
    start_server "${server_name}" "${server_entry}" ${server_config_file} ${start_args}
    local start_ret=$?
    if [ ${start_ret} -ne 0 ]; then
        echo -n "Start ${server_name} failed(error code: 1)" > "${result_file}"
        return 1
    fi

    # sleep 0.618 seconds, and then wait server login success
    sleep 0.618

    # wait loginserver start file
    wait_server_start_file ${server_name} "${start_file}"
    if [ $? -ne 0 ]; then
        log_err "Wait server start file failed, start ${server_name} failed!"
        \rm -rf "${start_file}"  # force cleanup start file again
        echo -n "Start ${server_name} failed(error code: 2)" > "${result_file}"
        return 2
    fi

    echo -n "Start ${server_name} success" > "${result_file}"

    log_info "done!"
}

function wait_server_start_file()
{
    local server_name="$1"
    local start_file="$2"
    local begin_wait=`date "+%s"`

    local wait_time=0
    local temp_file=".${server_name}.temp"

    log_info "wait for the ${server_name} to generate the startup successfully file..."
    while [ ! -f "${start_file}" ]; do
        echo -n "`list_server_status "${server_name}"`" > "${temp_file}"
        if egrep "Stopped" "${temp_file}" > /dev/null; then
            log_err "${server_name} stopped, failed to start server!"

            \rm -rf "${temp_file}"
            return 1
        fi

        sleep 10
        wait_time=$((${wait_time} + 10))
        log_info "wait for the ${server_name} to generate the startup successfully file(${wait_time} seconds)..."
        if [ ${wait_time} -ge ${____GAME_SERVER_START_MAX_WAIT} ]; then
            log_err "wait for the ${server_name} startup time too long, kill it!"

            \rm -rf "${temp_file}"
            stop_server "${____LOGIC_GAME}"

            \rm -rf "${start_file}"

            return 2
        fi
    done

    \rm -rf "${temp_file}"
    \rm -rf "${start_file}"

    return 0
}

function remove_server_start_file()
{
    local start_file="$1"
    \rm -rf "${start_file}"
}

function debugcontrol()
{
    local port=${1}
    local commond=${2}

    exec 3<>/dev/tcp/127.0.0.1/${port}
    if [ $? -ne 0 ]; then
        log_err ${commond} "failed"
        return 1
    fi

    echo "${commond}" >&3
    while read -r line
    do if [[ "$line" == "<CMD OK>" || "$line" == "<CMD Error>" ]]; then
        log_info "send ${commond}" $line;
        break;
    fi done <&3;exec 3<&-;exec 3>&-;

    return 0
}

function safestop_loginserver()
{
    local nodeid="`get_serverconf_loginnode_id`"
    local port="`exec_sql_cmd_on_confdb "SELECT port FROM conf_debug WHERE nodeid = ${nodeid}"`"
    debugcontrol ${port} "safestop exitlog"

    local args=$@
    stop_loginserver ${args}
}

function safestop_globalserver()
{
    local nodeid="`get_serverconf_globalnode_id`"
    local port="`exec_sql_cmd_on_confdb "SELECT port FROM conf_debug WHERE nodeid = ${nodeid}"`"
    debugcontrol ${port} "safestop exitlog"

    local args=$@
    stop_globalserver ${args}
}

function safestop_webserver()
{
    local nodeid="`get_serverconf_webnode_id`"
    local port="`exec_sql_cmd_on_confdb "SELECT port FROM conf_debug WHERE nodeid = ${nodeid}"`"
    debugcontrol ${port} "safestop exitlog"

    local args=$@
    stop_webserver ${args}
}

function safestop_gameserver()
{
    # check running or not
    local gs_st="`list_gameserver_status`"
    if `list_gameserver_status | egrep 'Stopped' > /dev/null`; then
        log_warn "gameserver not running"
        return 0
    fi

    # set gameserver status to maintain
    set_gameserver_logic_status 2
    if [ $? -ne 0 ]; then
        log_err "send gameserver status to <maintain> failed!"
        log_err "safe stop gameserver failed!"
        return 1
    fi

    # get telnet port
    log_info "get telnet port..."
    local gamenode_id="`get_serverconf_gamenode_id`"
    local telnet_port="`exec_sql_cmd_on_confdb "SELECT port FROM conf_debug WHERE nodeid = ${gamenode_id}"`"
    log_info "telnet port got: ${telnet_port}"

    # wait all agentlt services count down to 10 or less(we use python telnetlib standard lib to implement telnet access)
    local max_agentlt_count=20
    local temp_pycode_file=".safestop_temp_pycode_file"
    echo -e "from telnetlib import Telnet\nt = Telnet('127.0.0.1', ${telnet_port})\nt.write('list\\\n')\nagentlt_svcs_count = len([agentlt_svc for agentlt_svc in t.read_until('OK', 120).split('\\\n') if 'agentlt' in agentlt_svc])\nprint agentlt_svcs_count" > "${temp_pycode_file}"
    local check_agentlt_ok=FALSE
    local begin_check_time=`date "+%s"`
    local max_check_time=${____GAME_SERVER_STOP_MAX_WAIT}
    while [ "${check_agentlt_ok}" != "TRUE" ]; do
        local used_time=$((`date "+%s"` - ${begin_check_time}))
        if [ ${used_time} -ge ${max_check_time} ]; then
            log_err "wait <agentlt services count> down to ${max_agentlt_count} or less timeout(used: ${used_time})!"
            log_err "safe stop gameserver failed!"
            return 1
        fi

        local now_agentlt_svcs_count="`python "${temp_pycode_file}"`"
        if [ $? -ne 0 ]; then
            log_err "failed to get server <agentlt services> count, telnet error!"
            log_err "safe stop gameserver failed!"
            return 2
        fi

        log_info "wait for <agentlt services> count down to ${max_agentlt_count} or less(now: ${now_agentlt_svcs_count}, used ${used_time} seconds)..."
        if [ "${now_agentlt_svcs_count}" -lt 10 ]; then
            check_agentlt_ok=TRUE
        else
            sleep 3
        fi
    done

    rm -rf "${temp_pycode_file}"

    # wait 5 seconds, and then execute kill
    log_info "wait 5 seconds, and then execute force stop..."
    sleep 5

    debugcontrol ${telnet_port} "safestop exitlog"

    local args=$@
    stop_gameserver ${args}
}
