#!/bin/sh
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et

# installed by node_package (github.com/basho/node_package)

# Pull environment for this install
. "/usr/local/lib/riak/lib/env.sh"


# Keep track of where script was invoked
ORIGINAL_DIR=$(pwd)

# Make sure CWD is set to runner run dir
cd $RUNNER_BASE_DIR

# Identify the script name
SCRIPT=`basename $0`

usage() {
    echo "Usage: $SCRIPT {start | stop| restart | reboot | ping | console | attach | "
    echo "                    attach-direct | ertspath | chkconfig | escript | version | "
    echo "                    getpid | top [-interval N] [-sort reductions|memory|msg_q] [-lines N] }"
}

# All commands must either call bootstrap or bootstrapd
# Call bootstrap for non-daemon commands like ping or chkconfig
# Call bootstrapd for daemon commands like start/stop/console
bootstrap() {
    # Make sure the user running this script is the owner and/or su to that user
    check_user $@
    ES=$?
    if [ "$ES" -ne 0 ]; then
        exit $ES
    fi
}

bootstrapd() {
    # Create PID directory if it does not exist before dropping permissiongs
    # to the runner user
    create_pid_dir
    ES=$?
    if [ "$ES" -ne 0 ]; then
        echoerr "Unable to access $PID_DIR, permission denied, run script as root"
        exit 1
    fi

    # Now call bootstrap to drop to $RUNNER_USER
    bootstrap $@
}

# Check the first argument for instructions
case "$1" in
    start)
        # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
        bootstrapd $@

        # Make sure there is not already a node running
        node_down_check

        # Sanity check the app.config file
        check_config > /dev/null
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi

        # Warn the user if ulimit is too low
        check_ulimit

        # Make sure log directory exists
        mkdir -p $RUNNER_LOG_DIR

        HEART_COMMAND="$RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT start"
        export HEART_COMMAND
        mkdir -p $PIPE_DIR
        $ERTS_PATH/run_erl -daemon $PIPE_DIR/ $RUNNER_LOG_DIR \
            "exec $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT console" 2>&1

        if [ ! -z "$WAIT_FOR_PROCESS" ]; then
            # Wait for the node to come up. We can't just ping it because
            # distributed erlang comes up for a second before the node crashes
            # (eg. in the case of an unwriteable disk). Once the node comes
            # up we check for the $WAIT_FOR_PROCESS} process. If that's running
            # then we assume things are good enough. This will at least let
            # the user know when the node is crashing right after startup.
            WAIT=${WAIT_FOR_ERLANG:-15}
            while [ $WAIT -gt 0 ]; do
                WAIT=`expr $WAIT - 1`
                sleep 1

                # squash stderr output to not frighten users if the node does not
                # come up right away
                MUTE=`ping_node 2> /dev/null`
                if [ "$?" -ne 0 ]; then
                    continue
                fi
                PROCESS=`$NODETOOL rpcterms erlang whereis "'${WAIT_FOR_PROCESS}'."`
                if [ "$PROCESS" != "undefined" ]; then
                    # Attempt to create a .pid file for the process
                    create_pid_file
                    exit 0
                fi
            done
            echo "${SCRIPT} failed to start within ${WAIT_FOR_ERLANG:-15} seconds,"
            echo "see the output of '${SCRIPT} console' for more information."
            echo "If you want to wait longer, set the environment variable"
            echo "WAIT_FOR_ERLANG to the number of seconds to wait."
            exit 1
        fi

        # Attempt to create .pid file
        create_pid_file
        ;;

    stop)
        # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
        bootstrapd $@

        get_pid
        ES=$?
        if [ "$ES" -ne 0 ] || [ -z $PID ]; then
            exit $ES
        fi

        # Tell nodetool to stop
        $NODETOOL stop
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi

        # Now wait for the app to *really* stop
        while `kill -s 0 $PID 2>/dev/null`;
        do
            sleep 1
        done

        # remove pid file
        rm -f $PID_FILE
        ;;

    restart)
        # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
        bootstrapd $@

        ## Restart the VM without exiting the process
        $NODETOOL restart
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    reboot)
        # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
        bootstrapd $@

        ## Restart the VM completely (uses heart to restart it)
        $NODETOOL reboot
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    ping)
        # Bootstrap command (simply drop to $RUNNER_USER)
        bootstrap $@

        ## See if the VM is alive
        ping_node
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    attach-direct)
        # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
        bootstrapd $@

        # Allow attaching to a node without pinging it
        if [ "$2" = "-f" ]; then
          echo "Forcing connection..."
        else
          # Make sure a node is running
          node_up_check
        fi

        echo "Direct Shell: Use \"Ctrl-D\" to quit. \"Ctrl-C\" will terminate the $SCRIPT node."
        shift
        exec $ERTS_PATH/to_erl $PIPE_DIR
        ;;

    attach)
        # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
        bootstrapd $@

        # Make sure a node is running
        node_up_check

        echo "Remote Shell: Use \"Ctrl-C a\" to quit. q() or init:stop() will terminate the $SCRIPT node."
        shift
        NODE_NAME=${NAME_ARG#* }
        exec $ERTS_PATH/erl -name c_$$_$NODE_NAME -hidden -remsh $NODE_NAME $COOKIE_ARG
        ;;

    console)
        # Bootstrap daemon command (check perms & drop to $RUNNER_USER)
        bootstrapd $@

        RES=`ping_node`
        if [ "$?" -eq 0 ]; then
            echo "Node is already running - use '$SCRIPT attach' instead"
            exit 1
        fi

        # Sanity check the app.config file
        check_config
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi

        # Warn the user if ulimit -n is less than the defined threshold
        check_ulimit

        # Make sure log directory exists
        mkdir -p $RUNNER_LOG_DIR

        # Setup beam-required vars
        ROOTDIR=$RUNNER_BASE_DIR
        BINDIR=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
        EMU=beam
        PROGNAME=`echo $0 | sed 's/.*\///'`
        CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$RUNNER_SCRIPT \
             -config $RUNNER_ETC_DIR/app.config \
            -pa $RUNNER_PATCH_DIR \
            -args_file $RUNNER_ETC_DIR/vm.args -- ${1+"$@"}"
        export EMU
        export ROOTDIR
        export BINDIR
        export PROGNAME

        # Dump environment info for logging purposes
        echo "Exec: $CMD"
        echo "Root: $ROOTDIR"

        # Log the startup
        logger -t "$SCRIPT[$$]" "Starting up"

        # Start the VM
        exec $CMD
        ;;

    top)
        # Bootstrap command (simply drop to $RUNNER_USER)
        bootstrap $@

        # Make sure the local node IS running
        node_up_check

        shift
        MYPID=$$
        NODE_NAME=${NAME_ARG#* }
        $ERTS_PATH/erl -noshell -noinput \
            -pa $RUNNER_PATCH_DIR \
            -hidden $NAME_PARAM np_etop$MYPID$NAME_HOST $COOKIE_ARG \
            -s etop -s erlang halt -output text \
            -node $NODE_NAME \
            $* -tracing off
        ;;

    ertspath)
        echo $ERTS_PATH
        ;;

    chkconfig)
        # Bootstrap command (simply drop to $RUNNER_USER)
        bootstrap $@

        check_config
        ;;

    escript)
        # Bootstrap command (simply drop to $RUNNER_USER)
        bootstrap $@

        shift
        $ERTS_PATH/escript "$@"
        ES=$?
        if [ "$ES" -ne 0 ]; then
            exit $ES
        fi
        ;;

    version)
        echo $APP_VERSION
        ;;

    getpid)
        # Bootstrap command (simply drop to $RUNNER_USER)
        bootstrap $@

        # Get the PID from nodetool
        get_pid
        ES=$?
        if [ "$ES" -ne 0 ] || [ -z $PID ]; then
            exit $ES
        fi
        echo $PID
        ;;
    *)
        usage
        ;;
esac

exit 0
