#!/usr/bin/with-contenv bash # shellcheck shell=bash disable=SC1091,SC2015,SC2016 #--------------------------------------------------------------------------------------------- # Copyright (C) 2023, Ramon F. Kolb (kx1t) # # This program is free software: you can redistribute it and/or modify it # under the terms of the GNU General Public License as published by the # Free Software Foundation, either version 3 of the License, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, but # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along with this program. # If not, see . #--------------------------------------------------------------------------------------------- APPNAME="mlat-client" echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] Started as an s6 service" source /scripts/common source /scripts/interpret_ultrafeeder_config MLAT_CMD="/usr/bin/mlat-client" RESTARTTIMER=15 declare -A pid_array if [[ -z "${MLAT_CONFIG}" ]] then echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] Warning: MLAT_CONFIG not defined - MLAT will be disabled." sleep infinity fi if [[ -z "${MLAT_USER}" ]] && [[ -z "${UUID}" ]] then echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR: either UUID or MLAT_USER must be defined - MLAT will be disabled." sleep infinity fi if [[ -z "$LAT$READSB_LAT" ]]; then echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR: READSB_LAT or LAT must be defined - MLAT will be disabled." sleep infinity fi if [[ -z "$LONG$READSB_LON" ]]; then echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR: READSB_LON or LONG must be defined - MLAT will be disabled." sleep infinity fi if [[ -z "$ALT$READSB_ALT" ]]; then echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR: READSB_ALT or ALT must be defined - MLAT will be disabled." sleep infinity fi # MLAT_CONFIG has the following format: # MLAT_CONFIG=mlatserver_1,mlatserver_port_1,x1,y1,z1;mlatserver_2,mlatserver_port_2,x2,y2,z2 etc # where x1,y1,z1; x22,y2,z2; etc are optional and are interpreted as follows: # if it's a number, we'll assume it's a port number for return messages # if it starts with 'uuid=', it's a UUID number for that instance # anything else will be appended as extra parameter(s) to the mlat-client command line # parse MLAT_CONFIG string into mlat_configs array # Strip any extraneous spaces: MLAT_CONFIG="${MLAT_CONFIG#"${MLAT_CONFIG%%[![:space:]]*}"}" # strip leading space MLAT_CONFIG="${MLAT_CONFIG//; /;}" readarray -td ";" mlat_configs < <(printf '%s' "${MLAT_CONFIG}") # Now loop through the MLAT_CONFIG items and start up an Mlat_client for each of them: for instance in "${mlat_configs[@]}" do [[ -z "${instance}" ]] && continue || true # put individual params into the $params array: readarray -td "," params < <(printf '%s' "${instance}") uuid_arg=false extra_args="" # Check if the params array has values for the mandatory elements: if [[ -z "${params[0]}" ]] || [[ -z "${params[1]}" ]] then echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] ERROR -- MLAT_CONFIG is malformed: \"${instance}\". Stopping MLAT execution." # shellcheck disable=SC2046 kill $(ps -s $$ -o pid=) sleep infinity fi # ------------------------------------------------ # Build the MLAT parameter string: MLAT_PARAM=(--input-type "${MLAT_INPUT_TYPE}") MLAT_PARAM+=(--input-connect localhost:30005) MLAT_PARAM+=(--server "${params[0]}:${params[1]}") if [ -n "${LAT}" ]; then MLAT_PARAM+=(--lat "${LAT}") elif [ -n "${READSB_LAT}" ]; then MLAT_PARAM+=(--lat "${READSB_LAT}") fi if [ -n "${LONG}" ]; then MLAT_PARAM+=(--lon "${LONG}") elif [ -n "${READSB_LON}" ]; then MLAT_PARAM+=(--lon "${READSB_LON}") fi if [ -n "${ALT}" ]; then MLAT_PARAM+=(--alt "${ALT}") elif [ -n "${READSB_ALT}" ]; then MLAT_PARAM+=(--alt "${READSB_ALT}") fi if [[ -n "${MLAT_USER}" ]]; then MLAT_PARAM+=(--user "${MLAT_USER}") else rnd="${RANDOM}" echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] WARNING: MLAT_USER is not set - using random number \"${rnd}\" as MLAT_USER" MLAT_PARAM+=(--user "${rnd}") fi # Now process the rest of the arguments # The order doesn't matter, we'll do pattern matching: # If the argument is a number, then it must be the beast_results port # If the argument starts with "uuid=", then it must be a UUID # If the argument isn't any of the above, then it's an "extra argument" for ((i=2; i<${#params[*]}; i++)) do if [[ -n "${params[i]}" ]] && [[ "${params[i]}" =~ ^[0-9]+$ ]]; then # It's a number so it must be the return port MLAT_PARAM+=("--results beast,listen,${params[i]}") elif header="${params[i]:0:5}" && [[ "${header,,}" == "uuid=" ]]; then # It's a UUID MLAT_PARAM+=("--uuid ${params[i]:5}") uuid_arg=true else # It's an Extra Args string extra_args="$extra_args ${params[i]}" fi done # If no UUID was set in the argument strings, check if we can use the generic UUID parameter if [[ $uuid_arg == false ]] && [[ -n "${UUID}" ]]; then MLAT_PARAM+=("--uuid ${UUID}") fi # Now add the extra_args, if any: [[ -n "${extra_args}" ]] && MLAT_PARAM+=("${extra_args}") || true # ------------------------------------------------ # Create the command exec string: # shellcheck disable=SC2048,SC2086 execstring="$(echo ${MLAT_CMD} ${MLAT_PARAM[*]} | xargs)" # ------------------------------------------------ # Ready to launch, but wait until readsb is established... if ! pgrep readsb >/dev/null; then echo "[$(date +"%Y-%m-%d %H:%M:%S")][$APPNAME] Delaying start of MLAT client(s) until container is established..." while ! pgrep readsb >/dev/null do sleep 2 done fi sleep 10 # sleep a bit so everything is well established - starting readsb may take a bit # run this Mlat_client instance in the background: echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] starting: ${MLAT_CMD} ${MLAT_PARAM[*]}" if [[ -z "${LOGLEVEL}" ]] || [[ "${LOGLEVEL,,}" == "verbose" ]]; then { exec ${execstring} 2>&1 | stdbuf -o0 awk -v app="${APPNAME}" -v inst="${params[0]}" '{print "[" strftime("%Y-%m-%d %H:%M:%S", systime()) "][" app "][" inst "] " $0}'; } & elif [[ "${LOGLEVEL,,}" == "error" ]]; then { exec ${execstring} 2>&1 >/dev/null | stdbuf -o0 awk -v app="${APPNAME}" -v inst="${params[0]}" '{print "[" strftime("%Y-%m-%d %H:%M:%S", systime()) "][" app "][" inst "] " $0}'; } & elif [[ "${LOGLEVEL,,}" == "none" ]]; then { exec ${execstring} >/dev/null 2>/dev/null; } & fi # pid_array is indexed by the PID of each mlat_client and contains the MLAT_PARAMs for that instance # This is done so we can monitor them and restart them if needed pid_array[$!]="${MLAT_PARAM[*]}" sleep 5 done # All MLAT Clients are up, so set the flag. This flag is read by MLATHUB as a sign that it's # safe to start up touch /run/mlathub_up # Now iterate over all MLAT-client instances and check if they are still running: while true do for mlat_pid in "${!pid_array[@]}" do if ! kill -0 "${mlat_pid}" >/dev/null 2>&1 then # it exited - let's restart: sleep "${RESTARTTIMER}" [[ "${LOGLEVEL,,}" != "none" ]] && echo "[$(date +"%Y-%m-%d %H:%M:%S")][${APPNAME}] MLAT_Client $(awk '{print $6}' <<< "${pid_array[$mlat_pid]}") exited. Attempting to restart." || true # shellcheck disable=SC2086 execstring="$(echo ${MLAT_CMD} ${pid_array[$mlat_pid]} | xargs)" if [[ -z "${LOGLEVEL}" ]] || [[ "${LOGLEVEL,,}" == "verbose" ]]; then { exec ${execstring} 2>&1 | stdbuf -o0 awk -v app="${APPNAME}" -v inst="${params[0]}" '{print "[" strftime("%Y-%m-%d %H:%M:%S", systime()) "][" app "][" inst "] " $0}'; } & elif [[ "${LOGLEVEL,,}" == "error" ]]; then { exec ${execstring} 2>&1 >/dev/null | stdbuf -o0 awk -v app="${APPNAME}" -v inst="${params[0]}" '{print "[" strftime("%Y-%m-%d %H:%M:%S", systime()) "][" app "][" inst "] " $0}'; } & elif [[ "${LOGLEVEL,,}" == "none" ]]; then { exec ${execstring} >/dev/null 2>/dev/null; } & fi pid_array[$!]="${pid_array[${mlat_pid}]}" unset "pid_array[${mlat_pid}]" fi done sleep 10 done