#!/bin/bash
#
# Script to start bc-server.
#
# usage:
#   bc-server [--cluster _name_] [--force] --data path [server][:port] ...
#   bc-server --version
#   bc-server --help
#
# for full details see: https://beyondcron.com/docs/bc-server.html
#
# Copyright 2023 BeyondCron Pty Ltd and related entities / All rights reserved.

realPath() {
    path=$1
    target=$(readlink "${path}")

    while [ -n "${target}" ]; do
        path=$(cd $(dirname "${path}") && cd $(dirname "${target}") && pwd -P)/$(basename "${target}")
        target=$(readlink ${path})
    done

    if [ -d "${path}" ]; then
        path=$(cd "${path}" && pwd -P)
    elif [ -f "${path}" ]; then
        path=$(cd $(dirname "${path}") && pwd -P)/$(basename "${path}")
    fi

    echo "${path}"
}

self=$(realPath "$0")
dir=$(dirname "${self}")
name=$(basename "${self}")
rootDir=$(dirname "${dir}")

export BEYONDCRON_BIN_DIR=dir

cmd="${dir}/.${name}"
if [ ! -x "${cmd}" ]; then
    echo "$0: ${cmd} does not exist" >&2
    exit 1
fi

# find java
if [ -z "${JAVA_HOME}" ]; then
  if ( ! which java > /dev/null 2>&1 ); then
      echo "$0: could not find Java" >&2
      exit 1
  fi
  java='java'

else
  java="${JAVA_HOME}/bin/java"
  if [ ! -x "${java}" ]; then
    java="${JAVA_HOME}/jre/sh/java"
    if [ ! -x "${java}" ]; then
      echo "$0: could not find Java" >&2
      exit 1
    fi
  fi
fi

# confirm that we have found a supported version of Java
version=$( ${java} -version 2>&1 | grep version | cut -d'"' -f 2)
java_version=$( echo "$version" | cut -d'.' -f 1 )
if [[ ! "${java_version}" =~ ^[0-9]+$ ]]; then
  echo "$0: unexpected Java version number: $version" >&2
  exit 1
elif [ "${java_version}" -lt 11 ]; then
  echo "$0: Java ${java_version} is not supported, please use Java 11 or greater"
  exit 1
fi

# setup hazelcast logging and java modules
export BC_SERVER_OPTS="-Dprogram.name=${name} -Dhazelcast.logging.type=log4j2 --add-modules java.se --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED"

if [ "$rootDir" != '/opt/beyondcron' ] && [ -z "$BEYONDCRON_PROTECT_PROCESS_USER" ] && [ -O "$self" ]; then
  export BEYONDCRON_PROTECT_PROCESS_USER=false
fi

forceStartFile='/tmp/bc-server.force.start'
if [ -f ${forceStartFile} ]; then
    export BEYONDCRON_FORCE_START=true
    rm ${forceStartFile}
    if [ $? -ne 0 ]; then
        echo "$0: could not delete force start file ${forceStartFile}" >&2
        exit 1
    fi
fi

runningFile=${BEYONDCRON_RUNNING_FILE:-/tmp/beyondcron.running}
if [ -f "$runningFile" ]
then
  rm "$runningFile"
fi

if [ -n "${BEYONDCRON_ALERT_COMMAND}" ]; then
    alertCmd=${BEYONDCRON_ALERT_COMMAND}

    aCmd=$(echo "${alertCmd}" | cut -d' '  -f1)
    if [ ! -x "${aCmd}" ]; then
        echo "$0: alert command ${aCmd} does not exist" >&2
        exit 1
    fi
fi

stopSignal=${BEYONDCRON_SIGNAL_STOP:-WINCH}
if [ $(kill -l | grep -c "${stopSignal}") -ne 1 ]; then
  echo "$0: unknown stop signal ${stopSignal}, using WINCH instead" >&2
  stopSignal=$(kill -l WINCH)
elif [[ ! "$stopSignal" =~ ^[0-9]+$ ]]; then
  stopSignal=$(kill -l $stopSignal)
fi

termSignal=$(kill -l TERM)

trapSignal=0
trap 'echo "$0: stopping ${name} after receiving signal INT" >&2; trapSignal=${termSignal}; kill -TERM $childPid; ' INT
trap 'echo "$0: stopping ${name} after receiving signal TERM" >&2; trapSignal=${termSignal}; kill -TERM $childPid' TERM
trap 'echo "$0: shutting down ${name}"; trapSignal=${stopSignal}; kill -${stopSignal} $childPid' ${stopSignal}
trap '' HUP USR1 USR2

${cmd} "$@" &
childPid=$!
wait $childPid
result=$?
code=$(($result & 127))

while [ $result -ge 128 ] && [ $code -eq "$trapSignal" ]; do
  trapSignal=0
  wait $childPid
  result=$?
  code=$(($result & 127))
done

if [ $result -ge 128 ] && [ $code -eq "$stopSignal" ]; then
  code=0
fi

if [ ${code} -ne 0 ]; then
  export BEYONDCRON_DAEMON=${name}
  export BEYONDCRON_EXIT_CODE=${code}
  export BEYONDCRON_OS_USER=$(id -un)
  export BEYONDCRON_ALERT_REASON="${name} stopped after receiving signal ${code}"

  echo "$0: ${BEYONDCRON_ALERT_REASON}" >&2

  if [ -n "${alertCmd}" ]; then
    eval "${alertCmd}"
  fi

  if [ $result -ge 128 ]; then
    code=2
  fi

else
  echo "${name} shutdown"
fi

if [ -f "$runningFile" ]
then
  rm "$runningFile"
fi

exit ${code}

# end