#!/bin/bash
{% if osflavor=='centos' %}
#
#	/etc/rc.d/init.d/{{service}}
#
#	{{service}} - Provisioned using forever-service
#
# chkconfig: 2345 90 10 
# description: forever-service startup script for node script based service {{service}}, uses forever to start the service
# 
{% else %}
### BEGIN INIT INFO
# Provides: {{service}}
# Required-Start:    $network $remote_fs $local_fs
# Required-Stop:     $network $remote_fs $local_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: forever-service startup script for {{service}}
# Description: forever-service startup script for node script based service {{service}}, uses forever to start the service
### END INIT INFO
{% endif %}

#	CLI {{cli}}
#	Working Directory {{cwd}}

#Setup Environment variables (if any)
{% if envVarsArray|default(false) %}
{% for v in envVarsArray %}
export {{ v }}
{% endfor %}
{% endif %}

# Check if any of $pid (could be plural) are running
LOGFILE="/var/log/{{service}}.log"
{% if osflavor === 'centos' %}
LOCKFILE="/var/lock/subsys/{{service}}"
{% else %}
LOCKFILE="/var/lock/{{service}}"
{% endif %}
# introduce some gaps between restarts and throttle continous restarts
MIN_UPTIME="{{minUptime|default('5000')}}"
SPIN_SLEEP_TIME="{{spinSleepTime|default('2000')}}"

# kill signal: Since default needs to be SIGTERM, it is important that services gracefully shutdown,
# specially if they are doing transactions or other work which should not be interuppted in between
# for exceptional situation where you dont care about abrupt shutdown, SIGKILL should be used
KILL_SIGNAL="{{killSignal|default('SIGTERM')}}"

# Wait time afer with SIGKILL will be sent to the process, in case SIGTERM is not fully finished
# This is required since when we use SIGTERM, some times if there is problem in code, it might take lot of time for process to exit
# or process may never exit, in such siutation we have to forcebly kill it so that shutdown or service restart can be done appropriately
# this wait time is in millisecond
KILLWAITTIME={{forceKillWaitTime|default('5000')}}

killtree() {
    local _pid=$1
    local _sig=${2:--TERM}
    kill -stop ${_pid} # needed to stop quickly forking parent from producing children between child killing and parent killing
    for _child in $(ps -o pid --no-headers --ppid ${_pid}); do
        killtree ${_child} ${_sig}
    done
    kill -${_sig} ${_pid}
}

checkpidexists() {
	[ -d "/proc/$1" ] && return 0
	return 1
}



start() {
	#this is to ensure forever is able to find out the correct root every time
	export FOREVER_ROOT={{foreverRoot}}
    {% if runAsUser %}
    STATUS=$({{suprog}} - {{runAsUser}} -c "export FOREVER_ROOT={{foreverRoot}};{% if envVarsNameValueArray|default(false) %}{% for v in envVarsNameValueArray %}export {{ v[0] }}=$(printf "%q" {{v[1]}});{% endfor %}{% endif %}{{foreverPath}}forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{service}}\)\s.*\)/\2-status:\1/;tx;d;:x'")
    {% else %}
	STATUS=$({{foreverPath}}forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{service}}\)\s.*\)/\2-status:\1/;tx;d;:x')
	{% endif %}
	if ! [ -z "$STATUS" ]; then
		echo "Service {{service}} already running"
		return 0
	fi

	echo  "Starting {{service}}"



	{% if runAsUser %}
	touch $LOGFILE
	chown {{runAsUser}} $LOGFILE

	{{suprog}} - {{runAsUser}} -c "\
	export FOREVER_ROOT={{foreverRoot}};\
	{% if envVarsNameValueArray|default(false) %}{% for v in envVarsNameValueArray %}export {{ v[0] }}=$(printf "%q" {{v[1]}});\{% endfor %}{% else %}\{% endif %}
	cd {{cwd}};\{% if applyUlimits %}
	ulimit -f unlimited;\
    ulimit -t unlimited;\
    ulimit -v unlimited;\
    ulimit -n 64000;\
    ulimit -m unlimited;\
    ulimit -u 32000;\{% endif %}
    {{foreverPath}}forever \
    	-a \
    	-l $LOGFILE \
    	--minUptime $MIN_UPTIME \
    	--spinSleepTime $SPIN_SLEEP_TIME \
    	--killSignal $KILL_SIGNAL \
    	{{foreverOptions|default('')}} \
    	--uid {{service}} \
    	start {{script|default('app.js')}} {{scriptOptions|default('')}}" 2>&1 >/dev/null
	{% else %}
	# move to the directory from where the inital forever script was launched so that even if it is relative it works as expected
	cd {{cwd}}

	{% if applyUlimits %}
	ulimit -f unlimited
	ulimit -t unlimited
	ulimit -v unlimited
	ulimit -n 64000
	ulimit -m unlimited
	ulimit -u 32000
	{% endif %}

	{{foreverPath}}forever \
	-a \
	-l $LOGFILE \
	--minUptime $MIN_UPTIME \
	--spinSleepTime $SPIN_SLEEP_TIME \
	--killSignal $KILL_SIGNAL \
	{{foreverOptions|default('')}} \
	--uid {{service}} \
	start {{script|default('app.js')}} {{scriptOptions|default('')}} 2>&1 >/dev/null
	{% endif %}
	RETVAL=$?

 	[ $RETVAL = 0 ] && touch $LOCKFILE
 	return $RETVAL
}	

stop() {
	#this is to ensure forever is able to find out the correct root every time
	export FOREVER_ROOT={{foreverRoot}}

	echo -n "Shutting down {{service}}: "

    {% if runAsUser %}
    STATUS=$({{suprog}} - {{runAsUser}} -c "export FOREVER_ROOT={{foreverRoot}};{% if envVarsNameValueArray|default(false) %}{% for v in envVarsNameValueArray %}export {{ v[0] }}=$(printf "%q" {{v[1]}});{% endfor %}{% endif %}{{foreverPath}}forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{service}}\)\s.*\)/\2-status:\1/;tx;d;:x'")
    {% else %}
	STATUS=$({{foreverPath}}forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{service}}\)\s.*\)/\2-status:\1/;tx;d;:x')
	{% endif %}
	if [ -z "$STATUS" ]; then
		echo "Not running"
		return 0
	fi

	# PID=$(<$PIDFILE) - Changed to detection based on actual PID from forever, sicne due to watchDirectory pid could dynamically change
    {% if runAsUser %}
    PID=$({{suprog}} - {{runAsUser}} -c "export FOREVER_ROOT={{foreverRoot}};{% if envVarsNameValueArray|default(false) %}{% for v in envVarsNameValueArray %}export {{ v[0] }}=$(printf "%q" {{v[1]}});{% endfor %}{% endif %}{{foreverPath}}forever --plain list | sed -n -e '/data:\s*\[[0-9]*\]\s\({{service}}\)\s/p' | awk '{print \$7}'")
    {% else %}
	PID=$({{foreverPath}}forever --plain list | sed -n -e '/data:\s*\[[0-9]*\]\s\({{service}}\)\s/p' | awk '{print $7}')
	{% endif %}

	if [ -z "$PID" ]; then
		echo "Could not get pid"
		return 0
	fi

	#run in background, since recent changes in forever, now blocks stop call with SIGTERM is finished
	#but we want to wait till some time and forcibly kill after elapsed time
	#without background script, we could be waiting forever
	{% if runAsUser %}
	{{suprog}} - {{runAsUser}} -c "{{foreverPath}}forever stop {{service}}" 2>&1 >/dev/null &
	{% else %}
	{{foreverPath}}forever stop {{service}} 2>&1 >/dev/null &
	{% endif %}

	CURRENTWAITTIME=$KILLWAITTIME
	# wait for some time before forcefully killing the process
	while [ $CURRENTWAITTIME -gt 0 ]; do
		#check if the process is still running
		checkpidexists $PID
		if [ $? -ne 0 ]; then
			# if not running we can break, since no more wait is needed, service is stopped
			echo "Successful"
			break
		fi
		{% if osflavor === 'centos' %}
	 	usleep 500000
	 	let CURRENTWAITTIME-=500
	 	{% else %}
	 	sleep 1
	 	CURRENTWAITTIME=$(( $CURRENTWAITTIME - 1000))
	 	{% endif %}
	done
	checkpidexists $PID
	if [  $? -eq 0  ]; then
		killtree $PID 9
		echo 'Forced shutdown'
	fi

	rm -f $PIDFILE 2>&1 >/dev/null
	rm -f $LOCKFILE 2>&1 >/dev/null
	return 0

}

status() {
	#this is to ensure forever is able to find out the correct root every time
	export FOREVER_ROOT={{foreverRoot}}

    {% if runAsUser %}
    STATUS=$({{suprog}} - {{runAsUser}} -c "export FOREVER_ROOT={{foreverRoot}};{% if envVarsNameValueArray|default(false) %}{% for v in envVarsNameValueArray %}export {{ v[0] }}=$(printf "%q" {{v[1]}});{% endfor %}{% endif %}{{foreverPath}}forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{service}}\)\s.*\)/\2-status:\1/;tx;d;:x'")
    {% else %}
	STATUS=$({{foreverPath}}forever --plain list | sed 's/data:\(\s*\[[0-9]*\]\s*\({{service}}\)\s.*\)/\2-status:\1/;tx;d;:x')
	{% endif %}
	if [ -z "$STATUS" ]; then
		echo "{{service}} is not running"
		RETVAL=3
	else		
		echo $STATUS
		RETVAL=0
	fi
	return $RETVAL
}

case "$1" in
    start)
	start
	;;
    stop)
	stop
	;;
    status)
	status
	;;
    restart)
    	stop
	start
	;;
    *)
	echo "Usage: <servicename> {start|stop|status|restart}"
	exit 1
	;;
esac
exit $?
