#!/bin/bash
#
# Copyright 2019,2023 JS Foundation and other contributors, https://js.foundation/
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Node-RED Installer for RPM based systems

unset NODERED_HOME
umask 0022

usage() {
  cat << EOL

Usage: $0 [options]

options:
  --help                display this help and exits.
  --nodered-user=<user> specify the user to run as e.g. '--nodered-user=nodered'.
  --open-firewall       adding public firewall rule for node-red port 1880.
  --confirm-root        install as root without asking confirmation.
  --confirm-install     confirm the installation without asking a confirmation.

EOL
}

#NODE_VERSION=""

if [ $# -gt 0 ]; then
  # Parsing parameters
  while (( "$#" )); do
    case "$1" in
      --help)
        usage && exit 0
        shift
        ;;
      --confirm-root)
        CONFIRM_ROOT="y"
        shift
        ;;
      --confirm-install)
        CONFIRM_INSTALL="y"
        shift
        ;;
      --open-firewall)
        OPEN_FIREWALL="y"
        shift
        ;;
      --nodered-user=*)
        NODERED_USER="${1#*=}"
        shift
        ;;
      --) # end argument parsing
        shift
        break
        ;;
      -*|--*=) # unsupported flags
        echo "Error: Unsupported flag $1" >&2
        exit 1
        ;;
    esac
  done
fi

echo -ne "\033[2 q"
echo -en "\n      **************************************\n"
echo -en "      ***   \e[1;91mNode-RED\e[0;97m \e[1;97mRPM install Script\e[0m  ***\n"
echo -en "      **************************************\n"

# sanitize environment
case "${CONFIRM_ROOT}" in
      [Yy]* )
      export CONFIRM_ROOT=y
      ;;
      [Nn]* )
      export CONFIRM_ROOT=n
      ;;
      * )
      export CONFIRM_ROOT=n
      ;;
esac

case "${CONFIRM_INSTALL}" in
      [Yy]* )
      export CONFIRM_INSTALL=y
      ;;
      [Nn]* )
      export CONFIRM_INSTALL=n
      ;;
      * )
      export CONFIRM_INSTALL=n
      ;;
esac

# user requested, not root
if [[ -n "${NODERED_USER}" ]] &&  [[ "${NODERED_USER}" != "root" ]] && [[ "${CONFIRM_INSTALL}" == "n" ]]
then
    echo -en "\nThe sytem user is requested as \e[1;32m'${NODERED_USER}'\e[0m\r\n\r\n"
    read -p $'\e[0;97mAre you really sure you want to install as the target user \e[1;32m'"'${NODERED_USER}'"$'\e[0;97m? [\e[1;32my\e[0m/N] ?\e[0m' yn
    case $yn in
      [Yy]* )
      ;;
      * )
        exit
      ;;
    esac
fi

# user root requested
if [[ -n "${NODERED_USER}" ]] &&  [[ "${NODERED_USER}" == "root" ]] && [[ "${CONFIRM_ROOT}" == "n" ]]
then
    echo -en "\nThe sytem user is requested as \e[1;33m'${NODERED_USER}'\e[0m\r\n\r\n"
    read -p $'\e[0;97mAre you really sure you want to install as the target user \e[1;33m'"'${NODERED_USER}'"$'\e[0;97m? [\e[1;33my\e[0m/N] ?\e[0m' yn
    case $yn in
      [Yy]* )
      ;;
      * )
        exit
      ;;
    esac
fi

# no user requested, default to the current non root user
if [[ "${EUID}" != "0" ]] && [[ -z "${NODERED_USER}" ]] && [[ "${CONFIRM_INSTALL}" == "n" ]]
  then echo -en "\e[0;97m\nNo user has been set, this script is run as user '\e[1;33m${USER}\e[0;97m'.\r\n\r\n"
  read -p $'\e[0;97mWould you like to change to the recommended the target user to \e[1;32m\'nodered\'\e[0;97m? [\e[1;32my\e[0m/N] ' yn
  case $yn in
    [Yy]* )
    export NODERED_USER=nodered
    ;;
    * )
    ;;
  esac
fi

# no user requested, default to the current root user
if [[ "${EUID}" == "0" ]] && [[ -z "${NODERED_USER}" ]] && [[ "${CONFIRM_ROOT}" == "n" ]]
then
  echo -en "\nThe current user \e[1;33mroot\e[0m defaults as the target user for node-red install.\r\n\r\n"
  read -p $'\e[0;97mAre you really sure you want to install as the target user \e[1;31mroot\e[0;97m ? [\e[1;31my\e[0;97m/N] ?\e[0m' yn
  case $yn in
    [Yy]* )
    [[ -n "${NODERED_HOME}" ]] || export NODERED_HOME=/root;
    ;;
    * )
      exit
    ;;
  esac
fi




if [[ -z "${OPEN_FIREWALL}" ]] && [[ "${CONFIRM_INSTALL}" == "n" ]]
then
  OPEN_FIREWALL="n"
  read -r -t 15 -p $'\e[0;97mWould you like to add Node-RED port \e[34m1880\e[0;97m to the \e[1;34mfirewall\e[0;97m public zone ? [\e[1;34my\e[0;97m/N] ? ' response
  if [[ "$response" =~ ^([yY])+$ ]]; then
      OPEN_FIREWALL="y"
  fi
fi
# sanitize environment variable OPEN_FIREWALL
case "${OPEN_FIREWALL}" in
      [Yy]* )
      export OPEN_FIREWALL=y
      ;;
      [Nn]* )
      export OPEN_FIREWALL=n
      ;;
      * )
      export OPEN_FIREWALL=n
      ;;
esac

# this script assumes that $HOME is the folder of the user that runs node-red
# that $USER is the user name and the group name to use when running is the
# primary group of that user
# if this is not correct then edit the lines below
[[ -n "${NODERED_USER}" ]] || export NODERED_USER=$USER;
[[ -n "${NODERED_HOME}" ]] || export NODERED_HOME="/home/${NODERED_USER}"


# check internet, if failure exit
if curl -f https://www.npmjs.com/package/node-red  >/dev/null 2>&1
then
  echo " "
else
  echo " "
  echo "Sorry - cannot connect to internet - not going to touch anything."
  echo "https://www.npmjs.com/package/node-red   is not reachable."
  echo "Please ensure you have a working internet connection."
  echo " "
  exit 1
fi

# final install details
host=`hostname`
echo -e "\e[1;33m ${host}\e[0m : \e[1;97mNode-RED update \e[0;97m"
echo " "
echo -e "This script will do an install of node.js and \e[1;91mNode-RED\e[0;97m"
echo -e " with the service to auto-run as user \e[1;33m'${NODERED_USER}'\e[0m"
echo -e " in the home directory \e[1;37m'${NODERED_HOME}'\e[0m"
[[ "${OPEN_FIREWALL}" == "y" ]] && echo -e " with public \e[1;34mfirewall\e[0;97m port \e[34m1880\e[0;97m opened."
echo " "

# final confirmation of the install
yn="${CONFIRM_INSTALL}"
[[ "${yn}" == "y" ]] || read -p $'\e[1;97mAre you really \e[0m\e[1;32msure\e[1;97m you want to do this ?  [\e[1;32my\e[1;97m/N] ?\e[0m' yn
case "${yn}" in
    [Yy]* )
        sudo ()
        {
            [[ $EUID = 0 ]] || set -- command sudo "$@"
            "$@"
        }
        sudo useradd ${NODERED_USER}
        NODERED_GROUP=`id -gn ${NODERED_USER}`
        MYOS=$(cat /etc/*release | grep "^ID=" | cut -d = -f 2)
        versions='fedora"centos"rhel"ol"almalinux"rocky"miraclelinux"nobara"'
        if [[ $versions != *"${MYOS}"* ]]; then
            echo " "
            echo "Doesn't seem to be running on RedHat, Centos, Fedora, Rocky, Alma, Oracle Linux, MIRACLE LINUX or Nobara so quitting"
            echo " "
            exit 1
        fi
        GLOBAL="true"
        TICK='\033[1;32m\u2714\033[0m'
        CROSS='\033[1;31m\u2718\033[0m'
        sudo cd "${NODERED_HOME}" || exit 1
        clear
        echo -e "\n\e[0;97mRunning nodejs and Node-RED install for user '\e[1;33m${NODERED_USER}\e[0;97m' at '${NODERED_HOME}' on ${MYOS}\e[0m\n"
        time1=$(date)
        echo "" | sudo tee -a /var/log/nodered-install.log >>/dev/null
        echo "***************************************" | sudo tee -a /var/log/nodered-install.log >>/dev/null
        echo "" | sudo tee -a /var/log/nodered-install.log >>/dev/null
        echo "Started : "$time1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
        echo "Running for user $USER at $HOME" | sudo tee -a /var/log/nodered-install.log >>/dev/null
        echo -ne '  Stop Node-RED                       \r\n'
        echo -ne '  Install Node.js                     \r\n'
        echo -ne '  Install Node-RED core               \r\n'
        echo -ne '  Add shortcut commands               \r\n'
        echo -ne '  Update systemd script               \r\n'
        echo -ne '  Update public zone firewall rule    \r\n'
        echo -ne '                                      \r\n'
        echo -ne '\r\nAny errors will be logged to   /var/log/nodered-install.log\r\n'
        echo -ne '\033[9A'

        # stop any running node-red service
        if sudo systemctl stop nodered 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null ; then CHAR=$TICK; else CHAR=$CROSS; fi
        echo -ne "  Stop Node-RED                       $CHAR\r\n"

        # ensure ~/.config dir is owned by the user
        sudo chown -Rf ${NODERED_USER}:${NODERED_GROUP} ${NODERED_HOME}/.config
        echo "Now install nodejs" | sudo tee -a /var/log/nodered-install.log >>/dev/null
        # if [ "${MYOS}" = "fedora" ] || [ "${MYOS}" = "almalinux" ] || [ "${MYOS}" = "rocky" ] || [ "${MYOS}" = "miraclelinux" ]; then
        #     sudo dnf module reset -y nodejs 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
        #     if sudo dnf module install -y nodejs:18/default 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi
        # else
        #     if [ "$EUID" == "0" ]
        #     then
        #         if curl -fsSL https://rpm.nodesource.com/setup_18.x | bash - 2>&1 | tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi
        #     else
        #         if curl -fsSL https://rpm.nodesource.com/setup_18.x | sudo -E bash - 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi
        #     fi
        #     if sudo yum install -y nodejs 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi
        # fi

        sudo yum install https://rpm.nodesource.com/pub_18.x/nodistro/repo/nodesource-release-nodistro-1.noarch.rpm -y 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
        if sudo yum install nodejs -y --setopt=nodesource-nodejs.module_hotfixes=1 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi

        echo -ne "  Install Node.js LTS                 $CHAR"
        # sudo npm i -g npm 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null;
        hash -r
        rc=""
        if nov=$(node -v 2>/dev/null); then :; else rc="ERR"; fi
        if npv=$(npm -v 2>/dev/null); then :; else rc="ERR"; fi
        if [[ $rc == "" ]]; then
            echo -ne "   Node $nov   Npm $npv\r\n"
        else
            echo -ne "\b$CROSS   Failed to install Node.js - Exit\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n"
            exit 2
        fi

        # clean up the npm cache and node-gyp

        # and install Node-RED
        echo "Now install Node-RED" | sudo tee -a /var/log/nodered-install.log >>/dev/null
        if sudo npm i -g --unsafe-perm --no-progress node-red@latest 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi
        nrv=$(npm --no-progress -g ls node-red | grep node-red | cut -d '@' -f 2 | sudo tee -a /var/log/nodered-install.log) >>/dev/null 2>&1
        echo -ne "  Install Node-RED core               $CHAR   $nrv\r\n"

        echo "Now create basic package.json for the user" | sudo tee -a /var/log/nodered-install.log >>/dev/null
        sudo lastlog -u ${NODERED_USER} -C >>/dev/null 2>&1
        sudo su - ${NODERED_USER} <<'EOF'
             cd
	     mkdir -p ".node-red/node_modules"
             cd .node-red
             npm config set update-notifier false #2>&1 >>/dev/null
             if [ ! -f "package.json" ]; then
                echo '{' > package.json
                echo '  "name": "node-red-project",' >> package.json
                echo '  "description": "initially created for you by Node-RED '$nrv'",' >> package.json
                echo '  "version": "0.0.1",' >> package.json
                echo '  "dependencies": {' >> package.json
                echo '  }' >> package.json
                echo '}' >> package.json
            fi
EOF
        echo "Now add start/stop/reload/log scripts" | sudo tee -a /var/log/nodered-install.log >>/dev/null
        sudo mkdir -p /usr/bin
        if curl -f https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-icon.svg >/dev/null 2>&1
        then
            sudo curl -sL -o /usr/bin/node-red-start https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-start.rpm 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo curl -sL -o /usr/bin/node-red-stop https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-stop 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo curl -sL -o /usr/bin/node-red-restart https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-restart 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo curl -sL -o /usr/bin/node-red-reload https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-reload 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo curl -sL -o /usr/bin/node-red-log https://raw.githubusercontent.com/node-red/linux-installers/master/resources/node-red-log 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo curl -sL -o /etc/logrotate.d/nodered https://raw.githubusercontent.com/node-red/linux-installers/master/resources/nodered.rotate 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo chmod +x /usr/bin/node-red-start
            sudo chmod +x /usr/bin/node-red-stop
            sudo chmod +x /usr/bin/node-red-restart
            sudo chmod +x /usr/bin/node-red-reload
            sudo chmod +x /usr/bin/node-red-log
            echo -ne "  Add shortcut commands               $TICK\r\n"
        else
            echo -ne "  Add shortcut commands               $CROSS\r\n"
        fi

        # add systemd script and configure it for ${NODERED_USER}
        echo "Now add systemd script and configure it for ${NODERED_USER}:${NODERED_GROUP} @ ${NODERED_HOME}" | sudo tee -a /var/log/nodered-install.log >>/dev/null

        # check if systemd script already exists
        SYSTEMDFILE="/etc/systemd/system/nodered.service"

        if sudo curl -sL -o ${SYSTEMDFILE}.temp https://raw.githubusercontent.com/node-red/linux-installers/master/resources/nodered.service 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi
        # set the User,Group,EnvironmentFile and WorkingDirectory in nodered.service
        sudo sed -i 's#^User=pi#User='${NODERED_USER}'#;
                     s#^Group=pi#Group='${NODERED_GROUP}'#;
                     s#^WorkingDirectory=/home/pi#WorkingDirectory='${NODERED_HOME}'#;
                     s#^EnvironmentFile=-/home/pi/.node-red#EnvironmentFile=-/etc/node-red#;
                     s!^Environment="NODE_OPTIONS=--max_old_space_size=512"!#Environment="NODE_OPTIONS=--max_old_space_size=512"!' ${SYSTEMDFILE}.temp

        if test -f "${SYSTEMDFILE}"; then
            # there's already a systemd script
            EXISTING_FILE=$(md5sum ${SYSTEMDFILE} | awk '$1 "${SYSTEMDFILE}" {print $1}');
            TEMP_FILE=$(md5sum ${SYSTEMDFILE}.temp | awk '$1 "${SYSTEMDFILE}.temp" {print $1}');

            if [[ $EXISTING_FILE == $TEMP_FILE ]];
            then
                : # silent procedure
            else
                echo "Customized systemd script found @ ${SYSTEMDFILE}. To prevent loss of modifications, we'll not recreate the systemd script." | sudo tee -a /var/log/nodered-install.log >>/dev/null
                echo "If you want the installer to recreate the systemd script, please delete or rename the current script & re-run the installer." | sudo tee -a /var/log/nodered-install.log >>/dev/null
                CHAR="-   Skipped - existing script is customized."
            fi
            sudo rm ${SYSTEMDFILE}.temp
        else
            sudo mv ${SYSTEMDFILE}.temp ${SYSTEMDFILE}
        fi
        # make environment file for systemd
       	sudo mkdir -p /etc/node-red
        if test ! -f /etc/node-red/environment; then
          echo "# Node-RED EnvironmentFile for Systemd Service" | sudo tee -a /etc/node-red/environment >>/dev/null
          echo "#  after edit this file  `sudo systemctl restart nodered` to reload Node-red with the new options" | sudo tee -a /etc/node-red/environment >>/dev/null

          echo "" | sudo tee -a /etc/node-red/environment >>/dev/null
          echo "# uncomment and edit if running on low memory resource hardware" | sudo tee -a /etc/node-red/environment >>/dev/null
          echo "#NODE_OPTIONS=--max_old_space_size=512" | sudo tee -a /etc/node-red/environment >>/dev/null

          echo "" | sudo tee -a /etc/node-red/environment >>/dev/null
          echo "# uncomment next line and edit if you need an http proxy" | sudo tee -a /etc/node-red/environment >>/dev/null
          echo "#HTTP_PROXY=my.httpproxy.server.address" | sudo tee -a /etc/node-red/environment >>/dev/null

          echo "" | sudo tee -a /etc/node-red/environment >>/dev/null
          echo "# uncomment the next line for a more verbose log output" | sudo tee -a /etc/node-red/environment >>/dev/null
          echo "#NODE_RED_OPTIONS=-v" | sudo tee -a /etc/node-red/environment >>/dev/null
          echo "" | sudo tee -a /etc/node-red/environment >>/dev/null

          echo "Created /etc/node-red/environment for systemd service." | sudo tee -a /var/log/nodered-install.log >>/dev/null
       fi
        sudo systemctl daemon-reload 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
        echo -ne "  Update systemd script               $CHAR\r\n"

        if [[ ${OPEN_FIREWALL} == "y" ]]; then
            echo "Now add firewall rule for 1880" | sudo tee -a /var/log/nodered-install.log >>/dev/null
            if sudo curl -sL -o /etc/firewalld/services/nodered.xml https://raw.githubusercontent.com/node-red/linux-installers/master/resources/nodered.xml 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null; then CHAR=$TICK; else CHAR=$CROSS; fi
            sudo firewall-cmd --zone=public --add-service=nodered 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo firewall-cmd --reload 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo firewall-cmd --zone=public --add-service=nodered --permanent 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            sudo firewall-cmd --reload 2>&1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
            echo -ne "  Update public zone firewall rule    $CHAR\r\n"
        else
            echo "Not adding firewall rule" | sudo tee -a /var/log/nodered-install.log >>/dev/null
            echo -ne "  Not adding firewall rule            -\r\n"
        fi
        echo -ne "\r\n\r\n\r\n"
        echo -ne "All done.\r\n"
        echo -ne "  You can now start Node-RED with the command  \033[0;36mnode-red-start\033[0m\r\n"
        echo -ne "  Then point your browser to \033[0;36mlocalhost:1880\033[0m or \033[0;36mhttp://{your_ip-address}:1880\033[0m\r\n"
        echo -ne "\r\nStarted  $time1  -  Finished  $(date)\r\n\r\n"
        echo "Finished : "$time1 | sudo tee -a /var/log/nodered-install.log >>/dev/null
    ;;
    * )
        echo " "
        exit 1
    ;;
esac