#!/bin/bash


if [ -z "$NODE" ]; then
  NODE="streamer@server.l"
fi

BOOTARGS=""
ERLARGS=""

export ERL_CRASH_DUMP_SECONDS=0
export CUDA_DEVICE_ORDER=PCI_BUS_ID


# Use `systemctl edit flussonic` to set Environment variables e.g.
#
# [Service]
# Environment=ERL_MORE_OPTS="+JPperf true"
# Environment=ASYNC_THREADS="+A 1024"
# Environment=MEM="+MMmcs 30 +Mdai 0"
# Environment=SCHED="+stbt tnnps +SP 50:50"

# Deprecated way of setting environment vars
[ -f /etc/default/flussonic ] && . /etc/default/flussonic


# +zdbbl 20480      -- distribution buffer busy limit in kilobytes, couple of segments
DISTARGS=${DISTARGS-"+zdbbl 20480 -kernel inet_dist_use_interface {127,0,0,1} -kernel prevent_overlapping_partitions false"}


# production defaults

# +A 16             -- number of threads in async thread pool
# +a 2048           -- stack size in kilo words for threads in the async-thread pool
# +IOPt 30          -- number of IO poll threads to use, percentage of schedulers configured (i.e. of number of CPU cores)
# +IOPp 25          -- number of IO pollsets to use, percentage of number of poll threads
ASYNC_THREADS_DEFAULT="+A 16 +a 2048 +IOPt 30 +IOPp 25"

# +MMmcs 30         -- maximum possible memory segment cache
# +MBas aoffcaobf   -- binary allocator strategy
# +MBsbct 8192      -- binary allocations less than 8 MB go to multiblock carrier
# +MBsmbcs 64000 +MBlmbcs 128000 +MBmbcgs 3
#                   -- binary multiblock carrier sizes are 64..128 MB, large enough to not screw up Linux but not too large to keep footprint reasonable on 128-core systems
# +MBacul           -- When a utilization value > 0 is used, allocator instances are allowed to abandon multiblock carriers.
# +Mdai 16          -- max dirty allocator instances
MEM_DEFAULT="+MMmcs 30 +MBas aoffcaobf +MBsbct 8192 +MBsmbcs 64000 +MBlmbcs 128000 +MBmbcgs 3 +MBacul 10 +Mdai 16"

# +stbt db          -- bind schedulers to CPU cores if possible (some default spread), this should improve performance
# +sbwt short       -- schedulers go to sleep fast, releasing CPU to OS (for nice utilization in `top` tool)
# +swt low|medium|..-- how easily schedulers wake up to steal jobs. Early wakeups distribute work over multiple schedulers faster, but work does more easily bounce between schedulers.
# +sfwi 50          -- schedulers wake up often (50 ms) to check for new jobs
# +sub true         -- uniform job balancing (prefer all schedulers to be equally utilized)
# +zebwt short      -- ets busy wait threshold (may improve ets lock contention)
# +SDio 64          -- number of dirty IO threads, should be larger than number of disks in RAID
SCHED_DEFAULT="+stbt db  +sbwt short +swt medium +sfwi 50 +sub true  +zebwt short +SDio 64"



while [ $# -ge 1 ]; do
  opt="$1"
  OPTARG="$2"
  shift
  case $opt in
    --help|-h)
      echo "$0 [-n nodename] [-s server_id_path] [-c config_path] [-l log_dir] [-m snmp_dir] [-k known_hostname] \
[-p pidfile] [-b boot_error_file] [-a alias ip] -d"
      echo "  -n   default streamer@server.l:  nodename"
      echo "  -s   default priv/server.id or /etc/flussonic/server.id:  path to server id file"
      echo "  -c   default priv/flussonic.conf or /etc/flussonic/flussonic.conf:  path to config file"
      echo "  -l   default /var/log/flussonic:  path to log directory"
      echo "  -m   default /var/run/flussonic:  path to snmp directory"
      echo "  -k   default `hostname`:  hostname of flussonic as it shows to others"
      echo "  -p   default none:  path to pidfile"
      echo "  -a   hostname ip: alternative way to specify DNS hostname of some peer"
      echo "  -d   daemonize"
      echo "  -noinput   disable interactive console for systemd"
      exit 1
      ;;
    --node|-n)
      NODE=$OPTARG
      shift
      ;;
    --server_id_path|--server-id-path|-s)
      BOOTARGS="$BOOTARGS server_id_path $OPTARG"
      shift
      ;;
    --config|-c)
      BOOTARGS="$BOOTARGS config_path $OPTARG"
      CONFIG_PATH=$OPTARG
      shift
      ;;
    --logs|-l)
      BOOTARGS="$BOOTARGS log_dir $OPTARG"
      LOGDIR="$OPTARG"
      shift
      ;;
    --snmp_dir|--snmp-dir|-m)
      BOOTARGS="$BOOTARGS snmp_dir $OPTARG"
      shift
      ;;
    --hostname|-k)
      BOOTARGS="$BOOTARGS hostname $OPTARG"
      shift
      ;;
    --pid|-p)
      BOOTARGS="$BOOTARGS pid_path $OPTARG"
      PIDFILE="$OPTARG"
      shift
      ;;
    --bootlog|-b)
      BOOTARGS="$BOOTARGS boot_error_file $OPTARG"
      ERRORFILE="$OPTARG"
      shift
      ;;
    --alias|-a)
      host="${OPTARG}"
      shift
      ip="$1"
      shift
      BOOTARGS="$BOOTARGS alias $host $ip"
      ;;
    -noinput)
      ERLARGS="$ERLARGS -noinput"
      ;;
    --debug)
      BOOTARGS="$BOOTARGS debug_start"
      ;;
    --console_level|--console-level)
      BOOTARGS="$BOOTARGS console_level ${OPTARG}"
      shift
      ;;
    --daemonize|-d)
      DAEMONIZE=true
      ;;
    --json|-j)
      # JSON console output
      BOOTARGS="$BOOTARGS json"
      ;;
    *)
      echo "Invalid option '$opt' '$OPTARG'"
      exit 4
  esac
done

if [ "$PROD" = "true" ] || [ -f /opt/flussonic/bin/erl -a ! -e apps/manager/src ]; then
  export HOME=/etc/flussonic
  export PATH=/opt/flussonic/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin
  export LANG=C
  BOOTARGS="$BOOTARGS production"
  SCHED=${SCHED-$SCHED_DEFAULT}
  MEM=${MEM-$MEM_DEFAULT}
  ASYNC_THREADS=${ASYNC_THREADS-$ASYNC_THREADS_DEFAULT}
  ulimit -n 131072
  ARCH=`uname -m`
  if [ ! -f /etc/alpine-release -a "$ARCH" = "x86_64" ]; then
    export LD_PRELOAD=$(ls /opt/flussonic/lib/corelib-*/priv/os3_amd64.so)
  fi
  export PROCNAME=streamer
  if [ -w /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor -a "$ARCH" = "x86_64" ]; then
    for i in  /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor; do echo performance > $i; done
  fi
  # TODO: need remove, only tx2 case support
  if [ -e /sys/devices/tegra_udrm ]; then
    nvpmodel -m 0
    jetson_clocks
    echo 1 > /sys/kernel/debug/bpmp/debug/clk/nvenc/mrq_rate_locked
    echo 1 > /sys/kernel/debug/bpmp/debug/clk/nvdec/mrq_rate_locked
    cat /sys/kernel/debug/bpmp/debug/clk/nvdec/max_rate > /sys/kernel/debug/bpmp/debug/clk/nvdec/rate
    cat /sys/kernel/debug/bpmp/debug/clk/nvenc/max_rate > /sys/kernel/debug/bpmp/debug/clk/nvenc/rate
  fi

  if [ -f /.dockerenv ]; then
    DO_NOT_DO_NET_TUNING=yes
  fi

  if [ -z "$DO_NOT_DO_NET_TUNING" ]; then

    sysctl -w net.core.rmem_default=1048576
    sysctl -w net.core.rmem_max=1048576
    sysctl -w net.core.wmem_max=16777216

    sysctl -w net.ipv4.udp_mem="8388608 12582912 16777216"

    sysctl -w net.ipv4.tcp_wmem="4096 4194394 16777216"
    sysctl -w net.ipv4.tcp_congestion_control=htcp
    sysctl -w net.ipv4.tcp_slow_start_after_idle=0

    for DEV in /proc/sys/net/ipv4/conf/*/rp_filter
    do
        echo 0 > "$DEV"
    done

  fi

  export CHECK_SCALING_GOVERNOR=60
  if [ -d /opt/flussonic ]; then
    cd /opt/flussonic
  fi
else
  if [ ! -z ${CONFIG_PATH} ] && [ -d apps/web/priv/ssl ] && [ -f apps/web/priv/copy_ssl_certificate.sh ]; then
    DEST_CERT_PATH=$(dirname "${CONFIG_PATH}")
    SOURCE_CERT_PATH=apps/web/priv/ssl
    ./apps/web/priv/copy_ssl_certificate.sh -s=${SOURCE_CERT_PATH} -d=${DEST_CERT_PATH} &>/dev/null 
  fi
fi

if [ -z ${ERL_INETRC+x} ]; then
  if [ -f /etc/flussonic/.inetrc ]; then
    export ERL_INETRC=/etc/flussonic/.inetrc
  elif [ -f /opt/flussonic/.inetrc ]; then
    export ERL_INETRC=/opt/flussonic/.inetrc
  else
    export ERL_INETRC=`pwd`/deploy/packaging/root/opt/flussonic/.inetrc
  fi
fi

if [ -d _build/prod/opt/flussonic/lib/ ]; then
  export ERL_LIBS=_build/prod/opt/flussonic/lib/
elif [ -d _build/default/lib ]; then
  export ERL_LIBS=_build/default/lib
else
  export ERL_LIBS=/opt/flussonic/lib
fi

if [ "$PIDFILE" != "" ] && [ -f $PIDFILE ]; then
  if kill -0 `cat $PIDFILE` 2>/dev/null ; then
    echo "Seems that flussonic is running under pid `cat $PIDFILE`. Stop it first"
    exit 5
  fi
fi

# BEAM_TUNE must be constructed
#   * after filling default values for $ASYNC_THREADS $SCHED $MEM
#   * before usage in /opt/flussonic/bin/erl invocation
ERL_MORE_OPTS=${ERL_MORE_OPTS-""}
BEAM_TUNE=${BEAM_TUNE:-"$ASYNC_THREADS $SCHED $MEM $ERL_MORE_OPTS"}


if [ "$DAEMONIZE" = "true" ] ; then
  if [ "$PIDFILE" = "" ] || [ "$LOGDIR" = "" ] || [ "$ERRORFILE" = "" ] ; then
    echo "Cannot daemonize without pid file and logdir and boot error file"
    exit 5
  fi

  mkdir -p $LOGDIR/console
  mkdir -p `dirname $PIDFILE`/
  run_erl -daemon `dirname $PIDFILE`/ $LOGDIR/console "exec /opt/flussonic/bin/erl $BEAM_TUNE \
    -name $NODE -boot start_sasl -sasl errlog_type error \
    -s launcher start $BOOTARGS"

  i=0
  while [ $i -lt 100 -a ! -f "$PIDFILE" -a ! -f "$ERRORFILE" ] ; do 
    echo -n "."
    i=`expr $i + 1`
    sleep 1
  done 
  if [ -f "$PIDFILE" ] ; then
    echo "done"
  else 
    if [ -f "$ERRORFILE" ] ; then
      echo "failed: `cat $ERRORFILE`"
      rm -f $ERRORFILE
      exit 1
    fi
  fi

else
  exec /opt/flussonic/bin/erl $BEAM_TUNE \
    -name $NODE -boot start_sasl -sasl errlog_type error $ERLARGS $DISTARGS \
    -s launcher start $BOOTARGS
fi


