#!/usr/bin/env bash

. colors

export DEBIAN_FRONTEND=noninteractive
export LD_LIBRARY_PATH=/hive/lib


# miner minimal work time in seconds for log rotation
MINER_LOG_MIN_TIME=30

echo 500 > /proc/self/oom_score_adj

[[ ! -e $RIG_CONF ]] && echo "${RED}No rig config $RIG_CONF${NOCOLOR}" && exit 1
[[ ! -e $WALLET_CONF ]] && echo "${RED}No wallet config $WALLET_CONF${NOCOLOR}" && exit 1

source $RIG_CONF
source $WALLET_CONF


# Check arguments and miner
MINER_NAME="$1"
MINER_CMD="$2"
[[ -z $MINER_NAME ]] && echo "${RED}Give some miner name${NOCOLOR}" && exit 1
MINER_DIR=/hive/miners/$MINER_NAME

# define default fallback value
MINER_LOG_BASENAME=/var/log/miner/$MINER_NAME/$MINER_NAME

# Check base miner package ==========================================================================

UPDATED=0

# Checks in target of symlink exists
function mkfile_from_symlink() {
	[[ -z $1 ]] && return 1
	[[ ! -L $1 ]] && return 1 #not a symlink
	[[ -e $1 ]] && return 0 #symlink point to existing file
	local f=`readlink "$1"`
	local d=`dirname "$f"`
	[[ ! -d $d ]] && mkdir -p "$d" #&& echo "Creating $d"
	touch $f #&& echo "Touching $f"
	chown -R user "$d"
}


function rmfile_from_symlink() {
	[[ -z $1 ]] && return 0 #does not exist
	if [[ ! -L $1 ]]; then #not a symlink
		rm $1
		#echo "Deleting $1"
		return 0
	fi
	local f=`readlink "$1"`
	[[ -e $f ]] && rm $f #&& echo "Deleting $f" #symlink point to existing file
}


function hive-package-install() {
	local package_name=$1
	# write current status to miner status file
	echo '{"status":"installing", "status_text":"Installing package '$package_name'"}' > ${MINER_STATUS}${miner_nom}
	echo "${YELLOW}Installing $package_name${NOCOLOR}"
	if [[ $UPDATED -eq 0 ]]; then
		apt-wait
		#dpkg --configure -a
		hpkg fix
		hpkg update
		UPDATED=1
	fi
	for i in {1..2}; do
		apt-wait
		apt-get install -y $package_name 2>&1 | tee /tmp/package-install.log
		exitcode=${PIPESTATUS[0]}
		[[ $exitcode -eq 0 ]] && break
		sleep 1
	done
	if [[ $exitcode -ne 0 ]]; then
		echo '{"status":"error", "status_text":"Error installing package '$package_name'"}' > ${MINER_STATUS}${miner_nom}
		cat /tmp/package-install.log | message error "Error installing $package_name" payload
		return $exitcode
	fi
	apt-get clean
	echo
	return 0
}


function hive-package-version() {
	local package_name="$1"
	dpkg -s "$package_name" 2>/dev/null | grep -ioP "version:\s\K.*"
	return ${PIPESTATUS[0]}
}


function hive-package-exists() {
	local package_name="$1"
	dpkg -s "$package_name" 2>/dev/null | grep -q "installed"
}


function miner_export_params() {
	cd $MINER_DIR

	source $MINER_DIR/h-manifest.conf
	source $MINER_DIR/h-config.sh

	# exports needed by envsubst
	declare -fF miner_fork > /dev/null && # if function exists
		export MINER_FORK=`miner_fork` ||
		export MINER_FORK=
	export MINER_VER=`miner_ver`
	export MINER_API_PORT
	export MINER_LOG_BASENAME
}


function install_miner() {
	local root_updated=0
	local package_name="hive-miners-$MINER_NAME"
	hive-package-exists $package_name
	if [[ $? -ne 0 ]]; then
		# install miner root package
		hive-package-install $package_name || exit $?
		root_updated=1
	fi

	# check control files
	[[ ! -e $MINER_DIR ]] && echo "${RED}$MINER_DIR does not exist, check miner installation${NOCOLOR}" && install_result=1
	[[ ! -e $MINER_DIR/h-manifest.conf ]] && echo "${RED}No $MINER_DIR/h-manifest.conf${NOCOLOR}" && install_result=1
	[[ ! -e $MINER_DIR/h-config.sh ]] && echo "${RED}No h-config.sh found for $MINER_NAME${NOCOLOR}" && install_result=1
	[[ ! -e $MINER_DIR/h-run.sh ]] && echo "${RED}$MINER_DIR/h-run.sh is not implemented${NOCOLOR}" && install_result=1

	if [[ $install_result -ne 0 ]]; then
		echo '{"status":"error", "status_text":"Miner installing error, not found command file"}' > ${MINER_STATUS}${miner_nom}
		return $install_result
	fi

	if [[ $root_updated -eq 0 ]]; then
		# in subshell
		(
			miner_export_params
			update_root=0
			if [[ ! -z $MINER_FORK ]]; then
				package_name+="-"${MINER_FORK//_/-}
				hive-package-exists $package_name || update_root=1
			fi
			if [[ ! -z $MINER_VER ]]; then
				package_name+="-"${MINER_VER//_/-}
				hive-package-exists $package_name || update_root=1
			fi
			if [[ $update_root -eq 1 ]]; then
				hive-package-install "hive-miners-$MINER_NAME"
			fi
		)
	fi

	miner_export_params

	# Check actual miner's package
	if [[ ! -z $MINER_FORK ]]; then # install package of fork
		package_name+="-"${MINER_FORK//_/-}
		hive-package-exists $package_name || hive-package-install $package_name || exit $?
	fi
	if [[ ! -z $MINER_VER ]]; then # check version package
		package_name+="-"${MINER_VER//_/-}
		hive-package-exists $package_name || hive-package-install $package_name || exit $?
	fi
}


function config_miner() {
	miner_export_params

	echo
	echo "Miner:   ${CYAN}$MINER_NAME${NOCOLOR}"
	[[ ! -z $MINER_FORK ]] && echo "Fork:    ${YELLOW}$MINER_FORK${NOCOLOR}"
	[[ ! -z $MINER_VER ]] && echo "Version: ${YELLOW}$MINER_VER${NOCOLOR}"
	echo

	# used in benchmark. exiting before config generation
	[[ "$MINER_CMD" == "install" ]] && return 0

	# Generate config files after package is installed
	miner_config_gen
}


function run_miner() {
	LIBCURL3_COMPAT=

	miner_export_params

	# Ubuntu 18.04 compat
	[[ $LIBCURL3_COMPAT == 1 && -e /usr/lib/x86_64-linux-gnu/libcurl-compat.so.3.0.0 ]] &&
		export LD_PRELOAD=libcurl-compat.so.3.0.0

	# Drop TIME_WAIT sockets
	if [[ ! -z $MINER_API_PORT && -f /proc/net/tcpdropsock ]]; then
		echo ""
		while true; do
			sockets=$(netstat -n | grep ":$MINER_API_PORT " | grep WAIT)
			[[ -z "$sockets" ]] && break
			echo -e "${WHITE}Trying to release TIME_WAIT sockets:${NOCOLOR}\n$sockets\n"
			echo "$sockets" | awk '{print $4"\t"$5}' >/proc/net/tcpdropsock
			sleep 1
		done
	fi

	# start miner
	source $MINER_DIR/h-run.sh
}


[[ "$MINER_CMD" == "install" || -z $MINER_CMD ]] && miner_nom=1 || miner_nom=$MINER_CMD

# install miner packages, in subshell
( install_miner ) || exit $?

# generate config, in subshell
( config_miner ) || exit $?

# used in benchmark to install miners packages
[[ "$MINER_CMD" == "install" ]] && exit 0

# start watchdog here for primary miner
[[ "$MINER_NAME" == "$MINER" ]] && touch $RUNNING_FLAG

#write current status to miner status file
echo '{"status":"running"}' > ${MINER_STATUS}${miner_nom}

miner_start_ts=0
restart_count=0

while true; do
	# do not rotate logs if miner restarts quickly to keep old logs
	[[ $(date +%s) -lt $(( miner_start_ts + MINER_LOG_MIN_TIME )) ]] &&
		echo "${GRAY}Skipping miner log rotation due to execution time < ${MINER_LOG_MIN_TIME}sec${NOCOLOR}" ||
		miner logrotate $MINER_NAME

	miner_start_ts=$(date +%s)

	# prevent Ctrl+C from killing screen. only killing miner for first time
	trap 'echo ""' SIGINT

	# run miner, in subshell
	( run_miner )
	exitcode=$?

	# exit loop if miner stop exists
	[[ ! -z $MINER_STOP && -f $MINER_STOP ]] && break

	# allow Ctrl+C again
	trap - SIGINT

	# if restart count greater than 5 in first minute then write error status to miner status file
	[[ $restart_count -gt 5 && $(date +%s) -lt $(( miner_start_ts + 60 )) && `cat ${MINER_STATUS}${miner_nom} | jq -r '.status'` == "running" ]] && echo '{"status":"error", "status_text":"Miner starting error"}' > ${MINER_STATUS}${miner_nom}


	echo -e "\n${BYELLOW}$MINER_NAME${YELLOW} exited (exitcode=$exitcode), waiting to cooldown a bit${NOCOLOR}\n"
	((restart_count++))
	sleep 3
done

exit $exitcode
