#!/bin/bash
# This script extracts the platform build zip into the HapiApp2 directory.
# The build zip and checksum file are expected to already exist in HEDERA_USER_HOME_DIR,
# uploaded by the solo CLI before this script is invoked.
# Usage extract-platform <release-version>
# e.g. extract-platform v0.42.5
set -o pipefail

readonly HAPI_DIR=/opt/hgcapp/services-hedera/HapiApp2.0
readonly LOG_FILE="${HAPI_DIR}/output/extract-platform.log"
readonly MAIN_CLASS_PATTERN='[c]om.hedera.node.app.ServicesMain'
readonly NETWORK_NODE_SERVICE_DIR='/run/service/network-node'

function log() {
  local message="${1}"

  if [[ ! -f "${LOG_FILE}" ]]; then
    mkdir -p "${HAPI_DIR}/output"
    touch "${LOG_FILE}"
  fi

  printf "%s - %s\n" "$(date '+%Y-%m-%d %H:%M:%S')" "${message}" | tee -a "${LOG_FILE}"
}

function running_services_main_pids() {
  ps -eo pid,args | awk "/${MAIN_CLASS_PATTERN}/{print \$1}"
}

function ensure_services_main_stopped() {
  local pids
  pids="$(running_services_main_pids)"
  if [[ -z "${pids}" ]]; then
    return 0
  fi

  log "ServicesMain JVM detected before extraction; stopping network-node to avoid deleting jars under a live process"

  if [[ -x /command/network-node-lifecycle ]]; then
    /command/network-node-lifecycle stop > >(tee -a "${LOG_FILE}") 2>&1 || true
  fi

  # Force the service down at supervisor level so an emergency kill is not
  # immediately restarted by s6 while extraction is in progress.
  if [[ -d "${NETWORK_NODE_SERVICE_DIR}" ]] && [[ -x /command/s6-svc ]]; then
    /command/s6-svc -d "${NETWORK_NODE_SERVICE_DIR}" > >(tee -a "${LOG_FILE}") 2>&1 || true
  fi

  pids="$(running_services_main_pids)"
  if [[ -n "${pids}" ]]; then
    kill -TERM ${pids} > >(tee -a "${LOG_FILE}") 2>&1 || true
    sleep 5
  fi

  pids="$(running_services_main_pids)"
  if [[ -n "${pids}" ]]; then
    kill -KILL ${pids} > >(tee -a "${LOG_FILE}") 2>&1 || true
    sleep 2
  fi

  pids="$(running_services_main_pids)"
  if [[ -n "${pids}" ]]; then
    log "Failed to stop ServicesMain JVM before extraction; refusing to continue"
    return 1
  fi

  return 0
}

readonly tag="${1}"
if [[ -z "${tag}" ]]; then
  echo "Release tag is required (e.g. v0.42.5)"
  exit 1
fi

readonly HEDERA_USER_HOME_DIR=/home/hedera
readonly BUILD_ZIP_FILE="${HEDERA_USER_HOME_DIR}/build-${tag}.zip"
readonly CHECKSUM_FILE="${HEDERA_USER_HOME_DIR}/build-${tag}.sha384"

log "extract-platform.sh: begin................................"

ensure_services_main_stopped
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Pre-extraction stop check failed. Aborting extraction."
  exit 1
fi

# shellcheck disable=SC2164
cd ${HEDERA_USER_HOME_DIR}
ec="${?}"

if [[ "${ec}" -ne 0 ]]; then
  log "Failed to change directory to ${HEDERA_USER_HOME_DIR}. Error code: ${ec}"
  exit 1
fi

log "Verifying SHA sum of ${BUILD_ZIP_FILE} against ${CHECKSUM_FILE}"
sha384sum -c "${CHECKSUM_FILE}" > >(tee -a "${LOG_FILE}") 2>&1
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "SHA384 sum of ${BUILD_ZIP_FILE} does not match. Aborting."
  exit 1
fi

log "Deleting previous version under $HAPI_DIR/data/lib/*.jar and $HAPI_DIR/data/apps/*.jar"
rm -rvf ${HAPI_DIR}/data/lib/*.jar > >(tee -a "${LOG_FILE}") 2>&1
rm -rvf ${HAPI_DIR}/data/apps/*.jar > >(tee -a "${LOG_FILE}") 2>&1

# ensure the HapiApp2.0 directory exists
if [[ ! -d "${HAPI_DIR}" ]]; then
  log "Creating directory ${HAPI_DIR}"
  mkdir -p "${HAPI_DIR}" > >(tee -a "${LOG_FILE}") 2>&1
  ec="${?}"
  if [[ "${ec}" -ne 0 ]]; then
    log "Failed to create directory ${HAPI_DIR}"
    exit 1
  fi

  chown hedera:hedera "${HAPI_DIR}" > >(tee -a "${LOG_FILE}") 2>&1
  ec="${?}"
  if [[ "${ec}" -ne 0 ]]; then
    log "Failed to change ownership of ${HAPI_DIR} to the hedera user and group"
    exit 1
  fi
fi

# extract
echo "Using unzip to extract files"

# To avoid "Device or resource busy" error when unzip tries to delete pre-existing file first before extracting
# Uncompress to a temporary directory and then move the files to the target directory

mkdir -p /tmp/extract
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Failed to create temporary directory /tmp/extract. Error code: ${ec}"
  exit 1
fi

unzip -o "${BUILD_ZIP_FILE}" -d /tmp/extract > >(tee -a "${LOG_FILE}") 2>&1
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Failed to unzip ${BUILD_ZIP_FILE}. Error code: ${ec}"
  exit 1
fi

cp -rf /tmp/extract/data/lib/* "${HAPI_DIR}/data/lib/" > >(tee -a "${LOG_FILE}") 2>&1
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Failed to copy libraries from /tmp/extract/lib to ${HAPI_DIR}/data/lib. Error code: ${ec}"
  exit 1
fi

cp -rf /tmp/extract/data/apps/* "${HAPI_DIR}/data/apps/" > >(tee -a "${LOG_FILE}") 2>&1
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Failed to copy applications from /tmp/extract/apps to ${HAPI_DIR}/data/apps. Error code: ${ec}"
  exit 1
fi

cp -f /tmp/extract/VERSION "${HAPI_DIR}/VERSION" > >(tee -a "${LOG_FILE}") 2>&1
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Failed to copy VERSION file from /tmp/extract to ${HAPI_DIR}/VERSION. Error code: ${ec}"
  exit 1
fi

cp -f /tmp/extract/immediate.sh "${HAPI_DIR}/immediate.sh" > >(tee -a "${LOG_FILE}") 2>&1
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Failed to copy immediate.sh from /tmp/extract to ${HAPI_DIR}/immediate.sh. Error code: ${ec}"
  exit 1
fi

cp -f /tmp/extract/during-freeze.sh "${HAPI_DIR}/during_freeze.sh" > >(tee -a "${LOG_FILE}") 2>&1
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Failed to copy during-freeze.sh from /tmp/extract to ${HAPI_DIR}/during-freeze.sh. Error code: ${ec}"
  exit 1
fi

log "Removing temporary directory /tmp/extract"
rm -rf /tmp/extract > >(tee -a "${LOG_FILE}") 2>&1
ec="${?}"
if [[ "${ec}" -ne 0 ]]; then
  log "Failed to remove temporary directory /tmp/extract. Error code: ${ec}"
  exit 1
fi

log "................................end: extract-platform.sh"
exit 0
