diff --git a/bash-aliases b/bash-aliases index 0ebcbee..99d3508 100644 --- a/bash-aliases +++ b/bash-aliases @@ -3,6 +3,26 @@ shopt -s -o nounset +function wd-restart-web() { + local ka9q_web_pid_file=~/wsprdaemon/ka9q_web_daemon.pid + + if [[ ! -f ${ka9q_web_pid_file} ]]; then + echo "There is no file ${ka9q_web_pid_file}, so KA9Q-web server is not running" + return 0 + fi + local ka9q_web_pid=$(< ${ka9q_web_pid_file} ) + echo "Killing the KA9Q-web server with PID = ${ka9q_web_pid}" + kill ${ka9q_web_pid} + rc=$? + if [[ ${rc} -ne 0 ]]; then + echo "WARNING: found stale pid ${ka9q_web_pid} in ${ka9q_web_pid_file} since kill ${ka9q_web_pid} => ${rc}" + fi + rm ${ka9q_web_pid_file} + echo "Starting the KA9Q-web server (and any other WD services which aren't running)" + ~/wsprdaemon/wsprdaemon.sh -A +} + + ### On a Wsprsonde gateway, this function simplifies opening a terminal session to the WS through a USB connection function wd2ws(){ if [[ ! -e /dev/ttyACM0 ]]; then @@ -345,6 +365,7 @@ alias g='git' alias gc='git commit' alias gd='git diff' alias gs='git status' +alias gl='git log' ### Get pub file for a copy/past to remote server's .ssh/authorized_keys file alias catss='cat ~/.ssh/*pub' diff --git a/ka9q-utils.sh b/ka9q-utils.sh index b3ee5d2..b24c68a 100755 --- a/ka9q-utils.sh +++ b/ka9q-utils.sh @@ -24,13 +24,12 @@ declare KA9Q_TEMPLATE_FILE="${WSPRDAEMON_ROOT_DIR}/radiod@rx888-wsprdaemon-templ declare KA9Q_RADIO_ROOT_DIR="${WSPRDAEMON_ROOT_DIR}/ka9q-radio" declare KA9Q_RADIO_WD_RECORD_CMD="${KA9Q_RADIO_ROOT_DIR}/wd-record" declare KA9Q_RADIO_TUNE_CMD="${KA9Q_RADIO_ROOT_DIR}/tune" -declare KA9Q_GIT_URL="https://github.com/ka9q/ka9q-radio.git" declare KA9Q_DEFAULT_CONF_NAME="rx888-wsprdaemon" declare KA9Q_RADIOD_CONF_DIR="/etc/radio" declare KA9Q_RADIOD_LIB_DIR="/var/lib/ka9q-radio" ### These are the libraries needed by KA9Q, but it is too hard to extract them from the Makefile, so I just copied them here -declare KA9Q_PACKAGE_DEPENDANCIES="curl rsync build-essential libusb-1.0-0-dev libusb-dev libncurses-dev libfftw3-dev libbsd-dev libhackrf-dev \ +declare KA9Q_RADIO_LIBS_NEEDED="curl rsync build-essential libusb-1.0-0-dev libusb-dev libncurses-dev libfftw3-dev libbsd-dev libhackrf-dev \ libopus-dev libairspy-dev libairspyhf-dev librtlsdr-dev libiniparser-dev libavahi-client-dev portaudio19-dev libopus-dev \ libnss-mdns mdns-scan avahi-utils avahi-discover libogg-dev" @@ -39,95 +38,256 @@ declare KA9Q_RADIO_NWSIDOM="${KA9Q_RADIO_ROOT_DIR}/nwisdom" ### This is crea declare FFTW_DIR="/etc/fftw" ### This is the directory where radiod looks for a wisdomf declare FFTW_WISDOMF="${FFTW_DIR}/wisdomf" ### This the wisdom file it looks for -declare KA9Q_REQUIRED_COMMIT_SHA="${KA8Q_REQUIRED_COMMIT_SHA-3f4e93292526c3a1a8a037e0531e0457e6ebf9ae}" ### Defaults to Thu Aug 1 10:33:45 2024 -0700 declare GIT_LOG_OUTPUT_FILE="${WSPRDAEMON_TMP_DIR}/git_log.txt" ### function wd_logger() { echo $@; } ### Only for use when unit testing this file -function get_current_commit_sha() { - local __return_commit_sha_variable=$1 - local git_directory=$2 - local rc - - cd ${git_directory} >& /dev/null - rc=$? - if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: can't 'cd ${git_directory}'" - return 1 - fi - git log >& ${GIT_LOG_OUTPUT_FILE} - rc=$? - cd - > /dev/null - if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: directory ${git_directory} is not a git-created directory:\n$(< ${GIT_LOG_OUTPUT_FILE})" - return 2 - fi - local commit_sha=$( awk '/commit/{print $2; exit}' ${GIT_LOG_OUTPUT_FILE} ) - if [[ -z "${commit_sha}" ]]; then - wd_logger 1 "ERROR: 'git log' output does not contain a line with 'commit' in it" - return 3 - fi - wd_logger 2 "'git log' is returning the current commit SHA = ${commit_sha}" - eval ${__return_commit_sha_variable}=\${commit_sha} - return 0 -} - ### Ensure that the set of source code in a git-managed directory is what you want -### Returns: 0 => already that SHA, so no change 1 => successfully checked out that commit SHA, else 2,3,4 ERROR in trying to execute +### Returns: 0 => already that COMMIT, so no change 1 => successfully checked out that commit COMMIT, else 2,3,4 ERROR in trying to execute function pull_commit(){ local git_directory=$1 local desired_git_sha=$2 + local git_project=${git_directory##*/} local rc - local save_pwd=${PWD} - - cd ${git_directory} >& /dev/null - rc=$? - if [[ ${rc} -ne 0 ]]; then - cd ${save_pwd} - wd_logger 1 "ERROR: can't 'cd ${git_directory}'" + if [[ ! -d ${git_directory} ]]; then + wd_logger 1 "ERROR: project '${git_directory}' does not exist" return 2 fi + + if [[ ${desired_git_sha} =~ main|master ]]; then + wd_logger 2 "Loading the most recent COMMIT for project ${git_project}" + rc=0 + if [[ "$(cd ${git_directory}; git rev-parse HEAD)" == "$( cd ${git_directory}; git fetch origin && git rev-parse origin/${desired_git_sha})" ]]; then + wd_logger 2 "You have asked for and are on the latest commit of the main branch" + else + wd_logger 1 "You have asked for but are not on the latest commit of the main branch, so update the local copy of the code" + ( cd ${git_directory}; git fetch origin && git checkout origin/${desired_git_sha} ) >& git.log + rc=$? + if [[ ${rc} -ne 0 ]]; then + wd_logger 1 "ERROR: failed to update to latest commit:\n$(< git.log)" + else + wd_logger 1 "Updated to latest commit" + fi + fi + return ${rc} + fi + + ### desired COMMIT SHA was specified + local git_root="main" ### Now github's default. older projects like wsprdaemon have the root 'master' local current_commit_sha - get_current_commit_sha current_commit_sha $PWD + get_current_commit_sha current_commit_sha ${git_directory} rc=$? if [[ ${rc} -ne 0 ]]; then - cd ${save_pwd} - wd_logger 1 "ERROR: 'get_current_commit_sha current_commit_sha ${PWD}' => ${rc}" + wd_logger 1 "ERROR: 'get_current_commit_sha current_commit_sha ${git_director}' => ${rc}" return 3 fi if [[ "${current_commit_sha}" == "${desired_git_sha}" ]]; then - cd ${save_pwd} - wd_logger 2 "Current git commit SHA in ${PWD} is the expected ${current_commit_sha}" + wd_logger 2 "Current git COMMIT in ${git_directory} is the expected ${current_commit_sha}" return 0 fi - wd_logger 1 "Current git commit SHA in ${PWD} is ${current_commit_sha}, not the desired SHA ${desired_git_sha}, so update the code from git" - git checkout main >& /dev/null + wd_logger 1 "Current git commit COMMIT in ${git_directory} is ${current_commit_sha}, not the desired COMMIT ${desired_git_sha}, so update the code from git" + wd_logger 1 "First 'git checkout ${git_root}'" + ( cd ${git_directory}; git checkout ${git_root} ) >& git.log rc=$? if [[ ${rc} -ne 0 ]]; then - cd ${save_pwd} - wd_logger 1 "ERROR: 'git checkout origin/main' => ${rc}" + wd_logger 1 "ERROR: 'git checkout ${git_root}' => ${rc}. git.log:\n $(< git.log)" return 4 fi - git pull >& /dev/null + wd_logger 1 "Then 'git pull' to be sure the code is current" + ( cd ${git_directory}; git pull ) >& git.log rc=$? if [[ ${rc} -ne 0 ]]; then - cd ${save_pwd} - wd_logger 1 "ERROR: 'git pull' => ${rc}" + wd_logger 1 "ERROR: 'git pull' => ${rc}. git.log:\n$(< git.log)" return 5 fi - git checkout ${desired_git_sha} >& /dev/null + wd_logger 1 "Finally 'git checkout ${desired_git_sha}, which is the COMMIT we want" + ( cd ${git_directory}; git checkout ${desired_git_sha} ) >& git.log rc=$? if [[ ${rc} -ne 0 ]]; then - cd ${save_pwd} - wd_logger 1 "ERROR: 'git checkout ${desired_git_sha}' => ${rc}" + wd_logger 1 "ERROR: 'git checkout ${desired_git_sha}' => ${rc} git.log:\n$(< git.log)" return 6 fi - cd ${save_pwd} - wd_logger 1 "Successfully updated the ${git_directory} directory to SHA ${desired_git_sha}. Returned to $PWD" + wd_logger 1 "Successfully updated the ${git_directory} directory to COMMIT ${desired_git_sha}" return 1 } +############## +function wd_get_config_value() { + local __return_variable_name=$1 + local return_variable_type=$2 + + wd_logger 3 "Find the value of the '${return_variable_type}' from the config settings in the WD.conf file" + + if ! declare -p WSPR_SCHEDULE &> /dev/null ; then + wd_logger 1 "ERROR: the array WSPR_SCHEDULE has not been declared in the WD.conf file" + return 1 + fi + local -A receiver_reference_count_list=() + local schedule_index + for (( schedule_index=0; schedule_index < ${#WSPR_SCHEDULE[@]}; ++schedule_index )); do + local job_line="${WSPR_SCHEDULE[${schedule_index}]}" + wd_logger 3 "Getting the names and counts of radios defined for job ${schedule_index}: ${job_line}" + local job_line_list=( ${job_line} ) + local job_field + for job_field in ${job_line_list[@]:1}; do + local job_receiver=${job_field%%,*} + ((receiver_reference_count_list["${job_receiver}"]++)) + wd_logger 3 "Found receiver ${job_receiver} referenced in job ${job_field} has been referenced ${receiver_reference_count_list["${job_receiver}"]} times" + done + done + local largest_reference_count=0 + local most_referenced_receiver + local receiver_name + for receiver_name in "${!receiver_reference_count_list[@]}"; do + if [[ ${receiver_reference_count_list[${receiver_name}]} -gt ${largest_reference_count} ]]; then + largest_reference_count=${receiver_reference_count_list[${receiver_name}]} + most_referenced_receiver="${receiver_name}" + fi + done + wd_logger 3 "Found the most referenced receiver in the WSPR_SCHEDULE[] is '${most_referenced_receiver}' which was referenced in ${largest_reference_count} jobs" + + if ! declare -p RECEIVER_LIST >& /dev/null ; then + wd_logger 1 "ERROR: the RECEIVER_LIST array is not declared in WD.conf" + return 2 + fi + local receiver_index + for (( receiver_index=0; receiver_index < ${#RECEIVER_LIST[@]}; ++receiver_index )); do + local receiver_line_list=( ${RECEIVER_LIST[${receiver_index}]} ) + local receiver_name=${receiver_line_list[0]} + local receiver_call=${receiver_line_list[2]} + local receiver_grid=${receiver_line_list[3]} + + if [[ ${receiver_name} == ${most_referenced_receiver} ]]; then + case ${return_variable_type} in + CALLSIGN) + eval ${__return_variable_name}=\${receiver_call} + wd_logger 2 "Assigned ${__return_variable_name}=${receiver_call}" + return 0 + ;; + LOCATOR) + eval ${__return_variable_name}=\${receiver_grid} + wd_logger 2 "Assigned ${__return_variable_name}=${receiver_grid}" + return 0 + ;; + ANTENNA) + #local receiver_description=$( sed -n "/${receiver_name}.*${receiver_grid}/s/${receiver_name}.*${receiver_grid}//p" ${WSPRDAEMON_CONFIG_FILE} ) + local receiver_line=$( grep "\"${receiver_name} .*${receiver_grid}" ${WSPRDAEMON_CONFIG_FILE} ) + local antenna_description + if [[ "${receiver_line}" =~ \#.*ANTENNA: ]]; then + antenna_description="${receiver_line##*\#*ANTENNA:}" + shopt -s extglob + antenna_description="${antenna_description##+([[:space:]])}" ### trim off leading white space + wd_logger 2 "Found the description '${antenna_description}' in line: ${receiver_line}" + else + antenna_description="No antenna information" + wd_logger 2 "Can't find comments about receiver ${receiver_call}, so use 'No antenna information'" + fi + + eval ${__return_variable_name}="\${antenna_description}" + wd_logger 2 "Assigned ${__return_variable_name}=${antenna_description}" + return 0 + ;; + *) + wd_logger 1 "ERROR: invalid return_variable_type='${return_variable_type}" + return 0 + esac + fi + done + wd_logger 1 "ERROR: can't find ${return_variable_type} config information" + return 1 +} + +### Assumes ka9q-radio has been successfully installed and setup to run +function get_conf_section_variable() { + local __return_variable_name=$1 + local conf_file_name=$2 + local conf_section=$3 + local conf_variable_name=$4 + + if [[ ! -f ${conf_file_name} ]] ; then + wd_logger 1 "ERROR: '' doesn't exist" + return 1 + fi + local section_lines=$( grep -A 40 "\[.*${conf_section}\]" ${conf_file_name} | awk '/^\[/ {++count} count == 2 {exit} {print}' ) + if [[ -z "${section_lines}" ]]; then + wd_logger 1 "ERROR: couldn't find section '\[${conf_section}\]' in ${conf_file_name}" + return 2 + fi + wd_logger 2 "Got section '\[.*${conf_section}\]' in ${conf_file_name}:\n${section_lines}" + local section_variable_value=$( echo "${section_lines}" | awk "/${conf_variable_name} *=/ { print \$3 }" ) + if [[ -z "${section_variable_value}" ]]; then + wd_logger 1 "ERROR: couldn't find variable ${conf_variable_name} in ${conf_section} section of config file ${conf_file_name}" + return 3 + fi + eval ${__return_variable_name}="\${section_variable_value}" + wd_logger 2 "Returned the value '${section_variable_value}' of variable '${conf_variable_name}' in '${conf_section}' section of config file '${conf_file_name}' to variable '${__return_variable_name}'" + return 0 +} + + +function get_current_commit_sha() { + local __return_commit_sha_variable=$1 + local git_directory=$2 + local rc + + if [[ ! -d ${git_directory} ]]; then + wd_logger 1 "ERROR: directory '${git_directory}' doesn't exist" + return 1 + fi + ( cd ${git_directory}; git log ) >& ${GIT_LOG_OUTPUT_FILE} + rc=$? + if [[ ${rc} -ne 0 ]]; then + wd_logger 1 "ERROR: directory ${git_directory} is not a git-created directory:\n$(< ${GIT_LOG_OUTPUT_FILE})" + return 2 + fi + local commit_sha=$( awk '/commit/{print $2; exit}' ${GIT_LOG_OUTPUT_FILE} ) + if [[ -z "${commit_sha}" ]]; then + wd_logger 1 "ERROR: 'git log' output does not contain a line with 'commit' in it" + return 3 + fi + wd_logger 2 "'git log' is returning the current commit COMMIT = ${commit_sha}" + eval ${__return_commit_sha_variable}=\${commit_sha} + return 0 +} + +function ka9q-get-configured-radiod() { + local __return_radio_conf_file_name=$1 + + local _radiod_conf_file_name=$( ps aux | awk '!/awk/ && /\/sbin\/radiod /{print $NF}') + if [[ -n "${_radiod_conf_file_name}" ]]; then + wd_logger 2 "Found radiod is running and configured by ${_radiod_conf_file_name}" + eval ${__return_radio_conf_file_name}="\${_radiod_conf_file_name}" + return 0 + fi + wd_logger 2 "radiod isn't running, so find the conf file to use" + + local ka9q_conf_file_name + if [[ -z "${KA9Q_CONF_NAME-}" ]]; then + ka9q_conf_file_name=${KA9Q_RADIOD_CONF_DIR}/radiod@rx888-wsprdaemon.conf + wd_logger 2 "Found that KA9Q_CONF_NAME has not been defined in WD.conf, so use the default radiod conf file ${ka9q_conf_file_name}" + if [[ ! -f ${ka9q_conf_file_name} ]]; then + wd_logger 1 "ERROR: KA9Q_CONF_NAME was not defined in WD.conf, but the default ${ka9q_conf_file_name} doesn't exist" + exit 1 + fi + wd_logger 2 "The default radiod conf file ${ka9q_conf_file_name} has been found" + else + ka9q_conf_file_name=${KA9Q_RADIOD_CONF_DIR}/radiod@${KA9Q_CONF_NAME}.conf + wd_logger 2 "In WD.conf found KA9Q_CONF_NAME='${KA9Q_CONF_NAME}' => ${ka9q_conf_file_name}" + + if [[ ! -f ${ka9q_conf_file_name} ]]; then + wd_logger 1 "ERROR: The conf file ${ka9q_conf_file_nam} specified by KA9Q_CONF_NAME=${KA9Q__CONF_NAME} doesn't exist" + exit 1 + fi + wd_logger 2 "The configured radio conf file ${ka9q_conf_file_name} has been found" + fi + + eval ${__return_radio_conf_file_name}="\${ka9q_conf_file_name}" + wd_logger 2 "Assigned ${__return_radio_conf_file_name}='${ka9q_conf_file_name}'" + return 0 +} + + ### Checks that the radiod config file is set with the desired low = 1300, high = 1700 and fix them if they were set to 100, 5000 by WD 3.1.4 function ka9q_conf_file_bw_check() { local conf_name=$1 @@ -168,8 +328,6 @@ function ka9q_conf_file_bw_check() { } ### Parses the data fields in the first line with the word 'STAT' in it into the global associative array ka9q_status_list() -declare KA9Q_METADUMP_LOG_FILE="${KA9Q_METADUMP_LOG_FILE-/dev/shm/wsprdaemon/ka9q_metadump.log}" ### Put output of metadump here -declare KA9Q_METADUMP_STATUS_FILE="${KA9Q_STATUS_FILE-/dev/shm/wsprdaemon/ka9q.status}" ### Parse the fields in that file into seperate lines in this file declare KA9Q_MIN_LINES_IN_USEFUL_STATUS=20 declare KA9Q_GET_STATUS_TRIES=5 declare KA9Q_METADUMP_WAIT_SECS=${KA9Q_METADUMP_WAIT_SEC-5} ### low long to wait for a 'metadump...&' to complete @@ -371,8 +529,6 @@ function ka9q_status_service_test() { # function wd_logger() { echo $@; } ### Only for use when unit testing this file # function is_uint() { return 0; } -declare KA9Q_WEB_PID_FILE_NAME="./ka9q-web.pid" - function ka9q-get-conf-file-name() { local __return_pid_var_name=$1 local __return_conf_file_var_name=$2 @@ -423,8 +579,25 @@ function ka9q-get-status-dns() { ka9q-get-conf-file-name "ka9q_web_pid" "ka9q_web_conf_file" rc=$? if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "Can't get ka9q-get-conf-file-name, so radiod must not be running" - return 1 + wd_logger 1 "Can't get ka9q-get-conf-file-name, so no local radiod is running. See if radiod is running remotely" + avahi-browse -t -r _ka9q-ctl._udp 2> /dev/null | grep hf.*.local | sort -u > avahi-browse.log + local hf_locals_count=$(wc -l < avahi-browse.log) + local status_dns=$( sed -n 's/.*\[\(.*\)\].*/\1/p' avahi-browse.log ) + case ${hf_locals_count} in + 0) + wd_logger 1 "Can't find any hf...local streams" + return 1 + ;; + 1) + wd_logger 1 "Found one radiod outputing ${status_dns}, so there must be an active radiod service running remotely" + eval ${___return_status_dns_var_name}=\"${status_dns}\" + return 0 + ;; + *) + wd_logger 1 "Found ${hf_locals_count} radiod iservers running on this LAN. Chose which to listen to by adding a line to wsprdaemon.conf:\n$(< avahi-browse.log)" + return 1 + ;; + esac fi if [[ -z "${ka9q_web_conf_file}" || ! -f "${ka9q_web_conf_file}" ]]; then wd_logger 1 "Cant' find the conf file '${conf_file}' for radiod" @@ -447,9 +620,40 @@ function ka9q-get-status-dns() { #exit declare KA9Q_WEB_CMD="/usr/local/sbin/ka9q-web" -declare KA9Q_WEB_SETUP_LOG_FILE="${WSPRDAEMON_TMP_DIR}/ka9q_web_setup.log" + +declare ka9q_service_daemons_list=( + "hf1.local 8081 WW0WWV" +) + +### This is called by the watchdog daemon and needs to be extended to support multiple RX888 servers at a site. function ka9q_web_daemon() { + wd_logger 1 "Starting loop by checking for DNS of status stream" + + local ka9q_radiod_status_dns + ka9q-get-status-dns "ka9q_radiod_status_dns" >& /dev/null + rc=$? + if [[ ${rc} -ne 0 ]]; then + wd_logger 1 "ERROR: failed to find the status DNS => ${rc}" + else + ka9q_service_daemons_list[0]="${ka9q_radiod_status_dns} 8081 ${KA9Q_WEB_TITLE-RX888}" ### This is hack to get this one service imlmewntationb working + + local i + for (( i=0; i < ${#ka9q_service_daemons_list[@]}; ++i )); do + local ka9q_service_daemon_info="${ka9q_service_daemons_list[i]}" + + wd_logger 1 "Running 'ka9q_web_service_daemon '${ka9q_service_daemon_info}'" + ka9q_web_service_daemon ${ka9q_service_daemon_info} ### These should be spawned off + sleep 1 + done + fi + } + +function ka9q_web_service_daemon() { + + local status_dns_name=$1 ### Where to get the spectrum stream (e.g. hf.local) + local server_ip_port=$2 ### On what IP port to offer the UI + local server_description="$3" ### The description string at the top of the UI page while true; do if [[ ! -x ${KA9Q_WEB_CMD} ]]; then @@ -458,21 +662,12 @@ function ka9q_web_daemon() { wd_sleep 3 continue fi - - wd_logger 1 "Starting loop by checking for DNS of status stream" - - local ka9q_radiod_status_dns - ka9q-get-status-dns "ka9q_radiod_status_dns" >& /dev/null + local daemon_log_file="ka9q_web_service_${server_ip_port}.log" + wd_logger 1 "Got status_dns_name='${status_dns_name}', IP port = ${server_ip_port}, server description = '${server_description}" + ${KA9Q_WEB_CMD} -m ${status_dns_name} -p ${server_ip_port} -n "${server_description}" >& ${daemon_log_file} ### DANGER: nothing limits the size of this log file!!! rc=$? if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: failed to find the status DNS => ${rc}" - else - wd_logger 1 "Got ka9q_radiod_status_dns='${ka9q_radiod_status_dns}'" - ${KA9Q_WEB_CMD} -m ${ka9q_radiod_status_dns} >& ka9q_web_cmd.log ##/dev/null - rc=$? - if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: '${KA9Q_WEB_CMD} -m ${ka9q_radiod_status_dns}'=> ${rc}:\n$(< ka9q_web_cmd.log)" - fi + wd_logger 1 "ERROR: '${KA9Q_WEB_CMD} -m ${status_dns_name} -p ${server_ip_port} -n '${server_description}' => ${rc}:\n$(< ${daemon_log_file})" fi wd_logger 1 "Sleeping for 5 seconds before restarting" wd_sleep 5 @@ -484,227 +679,50 @@ function ka9q_web_daemon() { #} # test_ka9q-web-setup -function install_github_project() { - local project_subdir="$1" - local project_libs="${2//,/ }" - local project_url="$3" - local project_sha="$4" - local project_build_function="$5" - - wd_logger 2 "In subdir '${project_subdir}' install libs '${project_libs}' and then ensure installation of '${project_url}' with commit SHA '${project_sha}'" - - if [[ ${project_libs} != "NONE" ]] && ! install_dpkg_list ${project_libs}; then - wd_logger 1 "ERROR: 'install_dpkg_list ${project_libs}' => $?" - exit 1 - fi - - local build_needed="no" - if [[ -d ${project_subdir} ]]; then - local rc - ( cd ${project_subdir}; git remote -v | grep -q "${project_url}" ) ### Run in a subshell which returnes the status returned by grep - rc=$? - if [[ ${rc} -ne 0 ]]; then - echo wd_logger 1 "The clone of ${project_subdir} doesn't come from the configured ' ${project_url}', so delete the '${project_subdir}' directory so it will be re-cloned" - rm -rf ${project_subdir} - build_needed="yes" - fi - fi - - if [[ ! -d ${project_subdir} ]]; then - wd_logger 1 "Subdir ${project_subdir} does not exist, so 'git clone ${project_url}'" - git clone ${project_url} >& git.log - rc=$? - if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: 'git clone ${project_url} >& git.log' => ${rc}:\n$(< git.log)" - exit 1 - fi - build_needed="yes" - wd_logger 1 "Successful 'git clone ${project_url}'" - fi - - local project_real_path=$( realpath ${project_subdir} ) - wd_logger 2 "Ensure the correct SHA is installed 'pull_commit ${project_real_path} ${project_sha}'" - pull_commit ${project_real_path} ${project_sha} - rc=$? - if [[ ${rc} -eq 0 ]]; then - wd_logger 2 "The ${project_subdir} software was current, so compiling and installing are not needed" - elif [[ ${rc} -eq 1 ]]; then - build_needed="yes" - wd_logger 1 "KA9Q software was updated, so compile and install it" - else - wd_logger 1 "ERROR: git could not update KA9Q software" - exit 1 - fi - - if [[ ${build_needed} == "yes" ]]; then - wd_logger 1 "Project ${project_subdir} was newly cloned and/or a new commit was loaded from github. So build it" - if ! ${project_build_function} ${project_subdir} ; then - wd_logger 1 "ERROR: ${project_build_function} ${project_subdir} => $?" - exit 1 - fi - fi - return 0 -} - -### Not yet used... -function build_ka9q_radio(){ - if [[ ! -L ${KA9Q_RADIO_DIR}/Makefile ]]; then - if [[ -f ${KA9Q_RADIO_DIR}/Makefile ]]; then - wd_logger 1 "WARNING: ${KA9Q_RADIO_DIR}/Makefile exists but it isn't a symbolic link to ${KA9Q_RADIO_DIR}/Makefile.linux" - rm -f ${KA9Q_RADIO_DIR}/Makefile - fi - wd_logger 1 "Creating a symbolic link from ${KA9Q_RADIO_DIR}/Makefile.linux to ${KA9Q_RADIO_DIR}/Makefile" - ln -s ${KA9Q_RADIO_DIR}/Makefile.linux ${KA9Q_RADIO_DIR}/Makefile - ka9q_make_needed="yes" - fi -} - -declare ONION_LIBS_NEEDED="libgnutls28-dev libgcrypt20-dev cmake" -if [[ ${OS_RELEASE} =~ 24.04 ]]; then - ONION_LIBS_NEEDED="${ONION_LIBS_NEEDED} libgnutls30t64 libgcrypt20" -fi - -function build_onion() { - local project_subdir=$1 - local project_logfile="${project_subdir}-build.log" - - wd_logger 1 "Building ${project_subdir}" - ( - cd ${project_subdir} - mkdir -p build - cd build - cmake -DONION_USE_PAM=false -DONION_USE_PNG=false -DONION_USE_JPEG=false -DONION_USE_XML2=false -DONION_USE_SYSTEMD=false -DONION_USE_SQLITE3=false -DONION_USE_REDIS=false -DONION_USE_GC=false -DONION_USE_TESTS=false -DONION_EXAMPLES=false -DONION_USE_BINDINGS_CPP=false .. - make - sudo make install - sudo ldconfig - ) >& ${project_logfile} - rc=$? - if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: compile of '${project_subdir}' returned ${rc}:\n$( < ${project_logfile} )" - exit 1 - fi - wd_logger 1 "Done" - return 0 -} - -function build_ka9q_web() { +### This function is executed once the ka9q-radio dirrectory is created and has the configured version of SW installed +function build_ka9q_radio() { local project_subdir=$1 local project_logfile="${project_subdir}_build.log" - wd_logger 1 "Building ${project_subdir}" + wd_logger 2 "Starting" + find ${project_subdir} -type f -exec stat -c "%Y %n" {} \; | sort -n > before_make.txt + wd_logger 2 "Building ${project_subdir}" ( cd ${project_subdir} + if [[ ! -L Makefile ]]; then + if [[ -f Makefile ]]; then + wd_logger 1 "WARNING: Makefile exists but it isn't a symbolic link to Makefile.linux" + rm -f Makefile + fi + wd_logger 1 "Creating a symbolic link from Makefile.linux to Makefile" + ln -s Makefile.linux Makefile + fi make - sudo make install ) >& ${project_logfile} rc=$? if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: compile of 'ka9q-web' returned ${rc}:\n$(< ${project_logfile})" - exit 1 - fi - wd_logger 1 "Done" - return 0 -} - -# declare KA9Q_WEB_REPO="https://github.com/fventuri/ka9q-web 24af60d4895f4a0f6be0d6178664762389f91619" ### 'URL ' From Franco/Phil Fri Jul 19 15:46:12 2024 -0700 -# declare KA9Q_WEB_GITHUB_INFO="ka9q-web https://github.com/scottnewell/ka9q-web e8d289952a7a25e7b35521f6791e58e9cd41b299" ### 'URL ' From Scott Tue Dec 3 00:49:13 2024 +0000 -declare GITHUB_PROJECTS_LIST=( - "onion ${ONION_LIBS_NEEDED// /,} https://github.com/davidmoreno/onion ${ONION_SHA-de8ea938342b36c28024fd8393ebc27b8442a161} build_onion" - "ka9q-web NONE https://github.com/scottnewell/ka9q-web ${KA9Q_WEB_SHA-e8d289952a7a25e7b35521f6791e58e9cd41b299} build_ka9q_web" -) - -### -function ka9q-web-setup() { - local rc - wd_logger 2 "Starting in ${PWD}" - - local index - for (( index=0; index < ${#GITHUB_PROJECTS_LIST[@]}; ++index)) ; do - local project_info="${GITHUB_PROJECTS_LIST[index]}" - wd_logger 2 "Setup project '${project_info}'" - if ! install_github_project ${project_info} ; then - wd_logger 1 "ERROR: 'install_dpkg_list ${project_info}' => $?" - exit 1 - fi - done - wd_logger 2 "Done in ${PWD}" - return 0 -} - -function ka9q-radiod-setup() -{ - local rc - wd_logger 2 "Starting in ${PWD}" - - ### This has been called because A KA9Q rx has been configured, so we may need to install and compile ka9q-radio so that we can run the 'wd-record' command - if ! install_dpkg_list ${KA9Q_PACKAGE_DEPENDANCIES}; then - wd_logger 1 "ERROR: 'install_debian_package ${packages_needed}' => $?" + wd_logger 1 "ERROR: compile of '${project_subdir}' returned ${rc}:\n$(< ${project_logfile})" exit 1 fi - local ka9q_make_needed="no" - if [[ ! -d ${KA9Q_RADIO_DIR} ]]; then - wd_logger 1 "ka9q-radio subdirectory doesn't exist, so 'get clone' to create it and populate with source code" - git clone ${KA9Q_GIT_URL} - rc=$? - if [[ ${rc} -gt 1 ]]; then - wd_logger 1 "ERROR: 'git clone ${KA9Q_GIT_URL}' > ${rc}" + find ${project_subdir} -type f -exec stat -c "%Y %n" {} \; | sort -n > after_make.txt + diff before_make.txt after_make.txt > diff.log + rc=$? + case ${rc} in + 0) + wd_logger 2 "No new files were created, so no need for a 'sudo make install" + ;; + 1) + wd_logger 1 "New files were created, so run 'sudo make install" + ( cd ${project_subdir}; sudo make install ) >& ${project_logfile} + ;; + *) + wd_logger 1 "ERROR: 'diff before_make.txt after_make.txt' => ${rc}:\n$(< diff.log)" exit 1 - fi - ka9q_make_needed="yes" - fi + esac - ### If KA9Q software was loaded or updated, then it will need to be compiled and installed - if [[ ${KA9Q_GIT_PULL_ENABLED-yes} == "no" ]]; then - wd_logger 1 "Configured to not 'git pull' in the ka9q-radio/ directory" - else - pull_commit ${KA9Q_RADIO_DIR} ${KA9Q_REQUIRED_COMMIT_SHA} - rc=$? - if [[ ${rc} -eq 0 ]]; then - wd_logger 2 "KA9Q software was current, so compiling and installing may not be needed. Further checking will be done to determine it compiling is needed" - elif [[ ${rc} -eq 1 ]]; then - ka9q_make_needed="yes" - wd_logger 1 "KA9Q software was updated, so compile and install it" - else - wd_logger 1 "ERROR: git could not update KA9Q software" - exit 1 - fi - if [[ ! -L ${KA9Q_RADIO_DIR}/Makefile ]]; then - if [[ -f ${KA9Q_RADIO_DIR}/Makefile ]]; then - wd_logger 1 "WARNING: ${KA9Q_RADIO_DIR}/Makefile exists but it isn't a symbolic link to ${KA9Q_RADIO_DIR}/Makefile.linux" - rm -f ${KA9Q_RADIO_DIR}/Makefile - fi - wd_logger 1 "Creating a symbolic link from ${KA9Q_RADIO_DIR}/Makefile.linux to ${KA9Q_RADIO_DIR}/Makefile" - ln -s ${KA9Q_RADIO_DIR}/Makefile.linux ${KA9Q_RADIO_DIR}/Makefile - ka9q_make_needed="yes" - fi - fi - - if [[ ${ka9q_make_needed} == "yes" || ! -x ${KA9Q_RADIO_DIR}/wd-record ]]; then - wd_logger 1 "Compiling KA9Q-radio..." - cd ${KA9Q_RADIO_DIR} - if [[ ! -L Makefile ]]; then - ln -s Makefile.linux Makefile - fi - make clean >& /dev/null - make >& /dev/null - rc=$? - if [[ ${rc} -ne 0 ]]; then - cd - > /dev/null - wd_logger 1 "ERROR: failed 'make' of new KA9Q software => ${rc}" - return 1 - fi - sudo make install > /dev/null - rc=$? - cd - > /dev/null - if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: failed 'sudo make install' of new KA9Q software => ${rc}" - return 1 - fi - fi - - ### KA9Q has already been installed, so see if it needs to be started or restarted + ### KA9Q installed, so see if it needs to be started or restarted local ka9q_runs_only_remotely get_config_file_variable "ka9q_runs_only_remotely" "KA9Q_RUNS_ONLY_REMOTELY" if [[ ${ka9q_runs_only_remotely} == "yes" ]]; then @@ -847,139 +865,22 @@ function ka9q-radiod-setup() wd_logger 2 "KA9Q-radio failed to start" return 1 fi -} - -### Assumes ka9q-radio has been successfully installed and setup to run -function get_conf_section_variable() { - local __return_variable_name=$1 - local conf_file_name=$2 - local conf_section=$3 - local conf_variable_name=$4 - - if [[ ! -f ${conf_file_name} ]] ; then - wd_logger 1 "ERROR: '' doesn't exist" - return 1 - fi - local section_lines=$( grep -A 40 "\[.*${conf_section}\]" ${conf_file_name} | awk '/^\[/ {++count} count == 2 {exit} {print}' ) - if [[ -z "${section_lines}" ]]; then - wd_logger 1 "ERROR: couldn't find section '\[${conf_section}\]' in ${conf_file_name}" - return 2 - fi - wd_logger 2 "Got section '\[.*${conf_section}\]' in ${conf_file_name}:\n${section_lines}" - local section_variable_value=$( echo "${section_lines}" | awk "/${conf_variable_name} *=/ { print \$3 }" ) - if [[ -z "${section_variable_value}" ]]; then - wd_logger 1 "ERROR: couldn't find variable ${conf_variable_name} in ${conf_section} section of config file ${conf_file_name}" - return 3 - fi - eval ${__return_variable_name}="\${section_variable_value}" - wd_logger 2 "Returned the value '${section_variable_value}' of variable '${conf_variable_name}' in '${conf_section}' section of config file '${conf_file_name}' to variable '${__return_variable_name}'" - return 0 -} - -#function test_get_conf_section_variable() { -# get_conf_section_variable "test_value" /etc/radio/radiod@rx888-wsprdaemon.conf FT8 "data" -#} -#declare test_value -#test_get_conf_section_variable -#printf "%s\n" ${test_value} -#exit - -function ka9q-get-configured-radiod() { - local __return_radio_conf_file_name=$1 - - local _radiod_conf_file_name=$( ps aux | awk '!/awk/ && /\/sbin\/radiod /{print $NF}') - if [[ -n "${_radiod_conf_file_name}" ]]; then - wd_logger 2 "Found radiod is running and configured by ${_radiod_conf_file_name}" - eval ${__return_radio_conf_file_name}="\${_radiod_conf_file_name}" - return 0 - fi - wd_logger 2 "radiod isn't running, so find the conf file to use" - - local ka9q_conf_file_name - if [[ -z "${KA9Q_CONF_NAME-}" ]]; then - ka9q_conf_file_name=${KA9Q_RADIOD_CONF_DIR}/radiod@rx888-wsprdaemon.conf - wd_logger 2 "Found that KA9Q_CONF_NAME has not been defined in WD.conf, so use the default radiod conf file ${ka9q_conf_file_name}" - if [[ ! -f ${ka9q_conf_file_name} ]]; then - wd_logger 1 "ERROR: KA9Q_CONF_NAME was not defined in WD.conf, but the default ${ka9q_conf_file_name} doesn't exist" - exit 1 - fi - wd_logger 2 "The default radiod conf file ${ka9q_conf_file_name} has been found" - else - ka9q_conf_file_name=${KA9Q_RADIOD_CONF_DIR}/radiod@${KA9Q_CONF_NAME}.conf - wd_logger 2 "In WD.conf found KA9Q_CONF_NAME='${KA9Q_CONF_NAME}' => ${ka9q_conf_file_name}" - - if [[ ! -f ${ka9q_conf_file_name} ]]; then - wd_logger 1 "ERROR: The conf file ${ka9q_conf_file_nam} specified by KA9Q_CONF_NAME=${KA9Q__CONF_NAME} doesn't exist" - exit 1 - fi - wd_logger 2 "The configured radio conf file ${ka9q_conf_file_name} has been found" - fi - - eval ${__return_radio_conf_file_name}="\${ka9q_conf_file_name}" - wd_logger 2 "Assigned ${__return_radio_conf_file_name}='${ka9q_conf_file_name}'" - return 0 -} - -declare KA9Q_FT_TMP_ROOT="${KA9Q_FT_TMP_ROOT-/run}" ### The KA9q FT decoder puts its wav files in the /tmp/ftX/... trees and logs spots to /var/log/ftX.log -declare KA9Q_FT_TMP_ROOT_SIZE="${KA9Q_FT_TMP_ROOT_SIZE-100M}" - -declare KA9Q_DECODE_FT_CMD="/usr/local/bin/decode_ft8" ### hacked code which decodes both FT4 and FT8 -declare KA9Q_FT8_LIB_REPO_URL="https://github.com/ka9q/ft8_lib.git" ### Where to get that code -declare KA9Q_DECODE_FT8_DIR="${WSPRDAEMON_ROOT_DIR}/ft8_lib" ### Like ka9q-radio, ka9q-web amd onion, build 'decode-ft' in a subdirectory of WD's home - -function ka9q-ft-install-decode-ft() { - local rc - - wd_logger 1 "Starting in $PWD" - if [[ -x ${KA9Q_DECODE_FT_CMD} ]]; then - wd_logger 1 "${KA9Q_DECODE_FT_CMD}, so nothing to do" - return 0 - fi - wd_logger 1 "'${KA9Q_DECODE_FT_CMD}, so we need to create it" - if [[ ! -d ${KA9Q_DECODE_FT8_DIR} ]]; then - wd_logger 1 "'${KA9Q_DECODE_FT8_DIR}' doesn't exist, so we need to 'git clone' it" - git clone ${KA9Q_FT8_LIB_REPO_URL} - rc=$? - if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: 'git clone ${KA9Q_FT8_LIB_REPO_URL}' failed -> ${rc}" - return ${rc} - fi - wd_logger "Cloning was successful" - fi - - local start_pwd=${PWD} - cd ${KA9Q_DECODE_FT8_DIR} - git pull - rc=$? - if [[ ${rc} -ne 0 ]]; then - cd ${start_pwd} > /dev/null - wd_logger 1 "ERROR: 'git pull' => ${rc}" - return ${rc} - fi - make - rc=$? - if [[ ${rc} -ne 0 ]]; then - cd ${start_pwd} > /dev/null - wd_logger 1 "ERROR: 'make' => ${rc}" - return ${rc} - fi - sudo make install - rc=$? - if [[ ${rc} -ne 0 ]]; then - cd ${start_pwd} > /dev/null - wd_logger 1 "ERROR: 'sudo make install' => ${rc}" - return ${rc} - fi - cd ${start_pwd} > /dev/null - if [[ ! -x ${KA9Q_DECODE_FT_CMD} ]]; then - wd_logger 1 "ERROR: Can't create '${KA9Q_DECODE_FT_CMD}'" - return 1 - fi - wd_logger 1 "Successfully created '${KA9Q_DECODE_FT_CMD}'" - return 0 } +#function test_get_conf_section_variable() { +# get_conf_section_variable "test_value" /etc/radio/radiod@rx888-wsprdaemon.conf FT8 "data" +#} +#declare test_value +#test_get_conf_section_variable +#printf "%s\n" ${test_value} +#exit +declare KA9Q_FT_TMP_ROOT="${KA9Q_FT_TMP_ROOT-/run}" ### The KA9q FT decoder puts its wav files in the /tmp/ftX/... trees and logs spots to /var/log/ftX.log + +declare KA9Q_DECODE_FT_CMD="/usr/local/bin/decode_ft8" ### hacked code which decodes both FT4 and FT8 +declare KA9Q_FT8_LIB_REPO_URL="https://github.com/ka9q/ft8_lib.git" ### Where to get that code +declare KA9Q_DECODE_FT8_DIR="${WSPRDAEMON_ROOT_DIR}/ft8_lib" ### Like ka9q-radio, ka9q-web amd onion, build 'decode-ft' in a subdirectory of WD's home + function ka9q-ft-setup() { local ft_type=$1 ## can be 4 or 8 local ka9q_ft_tmp_dir=${KA9Q_FT_TMP_ROOT}/${ft_type} ### The ftX-decoded will create this directory and put the wav files it needs in it. We don't need to create it. @@ -1079,11 +980,13 @@ function ka9q-ft-setup() { ### In order that the jt9 spot line format matches that of 'decode-ft8', create a bash shell script which accepts the same arguments, runs jt9 and pipes its output through an awk script ### It is awkward to embed an awk script inline like this, but the alternative would be to add it to WD homne directory. When we strt using jt9 we should put it there. - local ka9q_ft_jt9_decoder="${ka9q_ft_tmp_dir}/wsjtx-ft-decoder.sh" + sudo mkdir -p ${ka9q_ft_tmp_dir} sudo chmod 777 ${ka9q_ft_tmp_dir} + local ka9q_ft_jt9_decoder="${ka9q_ft_tmp_dir}/wsjtx-ft-decoder.sh" wd_logger 2 "Creating ${ka9q_ft_jt9_decoder} ft_type=${ft_type}" # execlp( Modetab[Mode].decode, Modetab[Mode].decode, "-f", freq, sp->filename, (char *)NULL); + sudo rm -f ${ka9q_ft_jt9_decoder} echo -n "${JT9_CMD} -${ft_type#ft} \$3 | awk -v base_freq_ghz=\$2 -v file_name=\${3##*/} " > ${ka9q_ft_jt9_decoder} echo \''/^[0-9]/ { printf "%s %3d %4s %'\''12.1f ~ %s %s %s %s\n", 20substr(file_name,1,2)"/"substr(file_name,3,2)"/"substr(file_name,5,2)" "substr(file_name,8,2)":"substr(file_name,10,2)":"substr(file_name,12,2), $2, $3, @@ -1199,131 +1102,45 @@ function ka9q-ft-setup() { wd_logger 2 "Setup complete" } -declare KA9Q_PSK_REPORTER_URL="https://github.com/pjsg/ftlib-pskreporter.git" -declare KA9Q_PSK_REPORTER_DIR="${WSPRDAEMON_ROOT_DIR}/ftlib-pskreporter" - -function wd_get_config_value() { - local __return_variable_name=$1 - local return_variable_type=$2 - - wd_logger 3 "Find the value of the '${return_variable_type}' from the config settings in the WD.conf file" - - if ! declare -p WSPR_SCHEDULE &> /dev/null ; then - wd_logger 1 "ERROR: the array WSPR_SCHEDULE has not been declared in the WD.conf file" - return 1 - fi - local -A receiver_reference_count_list=() - local schedule_index - for (( schedule_index=0; schedule_index < ${#WSPR_SCHEDULE[@]}; ++schedule_index )); do - local job_line="${WSPR_SCHEDULE[${schedule_index}]}" - wd_logger 3 "Getting the names and counts of radios defined for job ${schedule_index}: ${job_line}" - local job_line_list=( ${job_line} ) - local job_field - for job_field in ${job_line_list[@]:1}; do - local job_receiver=${job_field%%,*} - ((receiver_reference_count_list["${job_receiver}"]++)) - wd_logger 3 "Found receiver ${job_receiver} referenced in job ${job_field} has been referenced ${receiver_reference_count_list["${job_receiver}"]} times" - done - done - local largest_reference_count=0 - local most_referenced_receiver - local receiver_name - for receiver_name in "${!receiver_reference_count_list[@]}"; do - if [[ ${receiver_reference_count_list[${receiver_name}]} -gt ${largest_reference_count} ]]; then - largest_reference_count=${receiver_reference_count_list[${receiver_name}]} - most_referenced_receiver="${receiver_name}" - fi - done - wd_logger 3 "Found the most referenced receiver in the WSPR_SCHEDULE[] is '${most_referenced_receiver}' which was referenced in ${largest_reference_count} jobs" +function build_ka9q_ft8() { + local project_subdir=$1 + local project_logfile="${project_subdir}_build.log" + local rc - if ! declare -p RECEIVER_LIST >& /dev/null ; then - wd_logger 1 "ERROR: the RECEIVER_LIST array is not declared in WD.conf" - return 2 + wd_logger 2 "Starting" + ( cd ${project_subdir}; if make; then sudo make install ; fi ; exit $? ) >& ${project_logfile} + rc=$? + if [[ ${rc} -ne 0 ]]; then + cd ${start_pwd} > /dev/null + wd_logger 1 "ERROR: 'make' => ${rc}" + return ${rc} fi - set +x - local receiver_index - for (( receiver_index=0; receiver_index < ${#RECEIVER_LIST[@]}; ++receiver_index )); do - local receiver_line_list=( ${RECEIVER_LIST[${receiver_index}]} ) - local receiver_name=${receiver_line_list[0]} - local receiver_call=${receiver_line_list[2]} - local receiver_grid=${receiver_line_list[3]} - - if [[ ${receiver_name} == ${most_referenced_receiver} ]]; then - case ${return_variable_type} in - CALLSIGN) - eval ${__return_variable_name}=\${receiver_call} - wd_logger 2 "Assigned ${__return_variable_name}=${receiver_call}" - return 0 - ;; - LOCATOR) - eval ${__return_variable_name}=\${receiver_grid} - wd_logger 2 "Assigned ${__return_variable_name}=${receiver_grid}" - return 0 - ;; - ANTENNA) - #local receiver_description=$( sed -n "/${receiver_name}.*${receiver_grid}/s/${receiver_name}.*${receiver_grid}//p" ${WSPRDAEMON_CONFIG_FILE} ) - local receiver_line=$( grep "\"${receiver_name} .*${receiver_grid}" ${WSPRDAEMON_CONFIG_FILE} ) - local antenna_description - if [[ "${receiver_line}" =~ \#.*ANTENNA: ]]; then - antenna_description="${receiver_line##*\#*ANTENNA:}" - shopt -s extglob - antenna_description="${antenna_description##+([[:space:]])}" ### trim off leading white space - wd_logger 2 "Found the description '${antenna_description}' in line: ${receiver_line}" - else - antenna_description="No antenna information" - wd_logger 2 "Can't find comments about receiver ${receiver_call}, so use 'No antenna information'" - fi - eval ${__return_variable_name}="\${antenna_description}" - wd_logger 2 "Assigned ${__return_variable_name}=${antenna_description}" - return 0 - ;; - *) - wd_logger 1 "ERROR: invalid return_variable_type='${return_variable_type}" - return 0 - esac + local save_rc=0 + local ft_type + for ft_type in ft8 ft4 ; do + ka9q-ft-setup ${ft_type} + rc=$? + if [[ ${rc} -ne 0 ]]; then + wd_logger 1 "ERROR: ka9q-jt-setup() ${ft_type} => ${rc}" + save_rc=${rc} + else + wd_logger 2 "Setup of ${ft_type} service is complete" fi done - set +x - wd_logger 1 "ERROR: can't find ${return_variable_type} config information" - return 1 -} + wd_logger 2 "Done" + return 0 +} -declare PSKREPORTER_REQUIRED_COMMIT_SHA=${PSKREPORTER_REQUIRED_COMMIT_SHA-9e6128bb8882df27f52e9fd7ab28b3888920e9c4} ### Default to 11/3/23 version which fixed a uploads missing problem and added wspr uploading +declare KA9Q_PSK_REPORTER_URL="https://github.com/pjsg/ftlib-pskreporter.git" +declare KA9Q_PSK_REPORTER_DIR="${WSPRDAEMON_ROOT_DIR}/ftlib-pskreporter" -function ka9q-psk-reporter-setup() { +function build_psk_uploader() { + local project_subdir=$1 local rc local psk_services_restart_needed="yes" - if [[ ! -d ${KA9Q_PSK_REPORTER_DIR} ]]; then - wd_logger 1 "No '${KA9Q_PSK_REPORTER_DIR}', so need to 'git clone to create it" - git clone ${KA9Q_PSK_REPORTER_URL} - rc=$? - if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: 'git clone ${KA9Q_PSK_REPORTER_URL}' => ${rc}" - return ${rc} - fi - if [[ ! -d ${KA9Q_PSK_REPORTER_DIR} ]]; then - wd_logger 1 "ERROR: Successfully cloned '${KA9Q_PSK_REPORTER_URL}' but '${KA9Q_PSK_REPORTER_DIR}' was not created, so the github repo is broken" - return 1 - fi - wd_logger 1 "Successfully cloned '${KA9Q_PSK_REPORTER_URL}'" - psk_services_restart_needed="yes" - fi - - pull_commit ${KA9Q_PSK_REPORTER_DIR} ${PSKREPORTER_REQUIRED_COMMIT_SHA} - rc=$? - if [[ ${rc} -eq 0 ]]; then - wd_logger 2 "PSKREPORTER software was current, so no restart may be needed" - elif [[ ${rc} -eq 1 ]]; then - wd_logger 1 "PSKREPORTER software was updated" - psk_services_restart_needed="yes" - else - wd_logger 1 "ERROR: git could not update PSKREPORTER software" - exit 1 - fi - if ! python3 -c "import docopt" 2> /dev/null; then rc=$? wd_logger 1 " python3 -c 'import docopt' => ${rc}. So install it" @@ -1351,7 +1168,7 @@ function ka9q-psk-reporter-setup() { wd_logger 1 "Successfully ran python3 -c 'import docopt'" fi - local pskreporter_sender_file_name="${KA9Q_PSK_REPORTER_DIR}/pskreporter-sender" ### This template file is part of the package + local pskreporter_sender_file_name="${project_subdir}/pskreporter-sender" ### This template file is part of the package local pskreporter_sender_bin_file_name="/usr/local/bin/pskreporter-sender" if [[ ! -x ${pskreporter_sender_bin_file_name} ]]; then wd_logger 1 "Copying ${pskreporter_sender_file_name} to ${pskreporter_sender_bin_file_name}" @@ -1359,7 +1176,7 @@ function ka9q-psk-reporter-setup() { sudo chmod a+x ${pskreporter_sender_bin_file_name} fi - local pskreporter_service_file_name="${KA9Q_PSK_REPORTER_DIR}/pskreporter@.service" ### This template file is part of the package + local pskreporter_service_file_name="${project_subdir}/pskreporter@.service" ### This template file is part of the package local pskreporter_systemd_service_file_name="/etc/systemd/system/pskreporter@.service" ### It should be copied to the /etc/systemd/system/ directory local needs_systemctl_daemon_reload="no" @@ -1488,60 +1305,177 @@ Environment=\"TZ=UTC\"" ${pskreporter_systemd_service_file_name} return 0 } -function ka9q_setup() { - wd_logger 2 "Starting in ${PWD}" +declare ONION_LIBS_NEEDED="libgnutls28-dev libgcrypt20-dev cmake" +if [[ ${OS_RELEASE} =~ 24.04 ]]; then + ONION_LIBS_NEEDED="${ONION_LIBS_NEEDED} libgnutls30t64 libgcrypt20" +fi - local active_receivers - get_list_of_active_real_receivers "active_receivers" - if ! [[ "${active_receivers}" =~ KA9Q ]]; then - wd_logger 1 "There are no KA9Q receivers in the conf file, so skip KA9Q setup" - return 0 - fi - wd_logger 2 "There are KA9Q receivers in the conf file, so set up KA9Q" - - ka9q-radiod-setup +function build_onion() { + local project_subdir=$1 + local project_logfile="${project_subdir}-build.log" + + wd_logger 2 "Building ${project_subdir}" + ( + cd ${project_subdir} + mkdir -p build + cd build + cmake -DONION_USE_PAM=false -DONION_USE_PNG=false -DONION_USE_JPEG=false -DONION_USE_XML2=false -DONION_USE_SYSTEMD=false -DONION_USE_SQLITE3=false -DONION_USE_REDIS=false -DONION_USE_GC=false -DONION_USE_TESTS=false -DONION_EXAMPLES=false -DONION_USE_BINDINGS_CPP=false .. + make + sudo make install + sudo ldconfig + ) >& ${project_logfile} rc=$? if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: ka9q-radiod-setup() => ${rc}" - return ${rc} - fi - wd_logger 2 "ka9q-radiod is setup ${PWD}" - if [[ ${KA9Q_RUNS_ONLY_REMOTELY-no} == "yes" ]]; then - wd_logger 2 "Ka9q-radio is setup but we are configured to not run radiod remotely. So don't setup KA9Q-web" - return 0 - fi + wd_logger 1 "ERROR: compile of '${project_subdir}' returned ${rc}:\n$( < ${project_logfile} )" + exit 1 + fi + wd_logger 2 "Done" + return 0 +} + +function build_ka9q_web() { + local project_subdir=$1 + local project_logfile="${project_subdir}_build.log" - ka9q-web-setup + wd_logger 2 "Building ${project_subdir}" + ( + cd ${project_subdir} + make + sudo make install + ) >& ${project_logfile} rc=$? + if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: ka9q-web-setup() => ${rc}" - else - wd_logger 2 "Both radiod and ka9q-web are setup" + wd_logger 1 "ERROR: compile of 'ka9q-web' returned ${rc}:\n$(< ${project_logfile})" + exit 1 fi + wd_logger 2 "Done" + return 0 +} - local save_rc=0 - local ft_type - for ft_type in ft8 ft4 ; do - ka9q-ft-setup ${ft_type} +function install_github_project() { + local project_subdir="$1" + local project_commit_check="$2" ## yes by default, but can be defined in WD.conf + local project_run"$3" ## yes by default, but can be defined in WD.conf + local project_build_function="$4" + local project_libs="${5//,/ }" + local project_url="$6" + local project_sha="$7" + + wd_logger 2 "In subdir '${project_subdir}' install libs '${project_libs}' and then ensure installation of '${project_url}' with commit COMMIT '${project_sha}'" + + if [[ ${project_libs} != "NONE" ]] && ! install_dpkg_list ${project_libs}; then + wd_logger 1 "ERROR: 'install_dpkg_list ${project_libs}' => $?" + exit 1 + fi + + if [[ -d ${project_subdir} ]]; then + local rc + ( cd ${project_subdir}; git remote -v | grep -q "${project_url}" ) ### Run in a subshell which returnes the status returned by grep rc=$? if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: ka9q-jt-setup() ${ft_type} => ${rc}" - save_rc=${rc} - else - wd_logger 2 "Setup of ${ft_type} service is complete" + echo wd_logger 1 "The clone of ${project_subdir} doesn't come from the configured ' ${project_url}', so delete the '${project_subdir}' directory so it will be re-cloned" + rm -rf ${project_subdir} + fi + fi + + if [[ ! -d ${project_subdir} ]]; then + wd_logger 1 "Subdir ${project_subdir} does not exist, so 'git clone ${project_url}'" + git clone ${project_url} >& git.log + rc=$? + if [[ ${rc} -ne 0 ]]; then + wd_logger 1 "ERROR: 'git clone ${project_url} >& git.log' => ${rc}:\n$(< git.log)" + exit 1 + fi + wd_logger 1 "Successful 'git clone ${project_url}'" + fi + + case ${project_commit_check} in + no) + wd_logger 1 "Skipping commit check for project '${project_subdir}'" + ;; + yes|main|master) + local pull_commit_target=${project_sha} + if [[ ${project_commit_check} != "yes" ]]; then + pull_commit_target=${project_commit_check} + wd_logger 1 "Project ${project_subdir} has been configured to load the latest ${pull_commit_target} branch commit" + fi + local project_real_path=$( realpath ${project_subdir} ) + wd_logger 2 "Ensure the correct COMMIT is installed by running 'pull_commit ${project_real_path} ${project_sha}'" + pull_commit ${project_real_path} ${pull_commit_target} + rc=$? + if [[ ${rc} -eq 0 ]]; then + wd_logger 2 "The ${project_subdir} software was current" + elif [[ ${rc} -eq 1 ]]; then + wd_logger 1 "KA9Q software was updated, so compile and install it" + else + wd_logger 1 "ERROR: git could not update KA9Q software" + exit 1 + fi + ;; + *) + wd_logger 1 "ERROR: ${project_commit_check}=${project_commit_check}" + exit + ;; + esac + + wd_logger 2 "Run ${project_build_function}() in ${project_subdir}" + if ! ${project_build_function} ${project_subdir} ; then + wd_logger 1 "ERROR: ${project_build_function} ${project_subdir} => $?" + exit 1 + fi + return 0 +} + +### The GITHUB_PROJECTS_LIST[] entries define additional Linux services which may be installed and started by WD. Each line has the form: +### "~/wsprdaemon/ check_git_commit[yes/no] start_service_after_installation[yes/no] service_specific_bash_installation_function_name linux_libraries_needed_list(comma-seperated) git_url git_commit_wanted +declare GITHUB_PROJECTS_LIST=( + "ka9q-radio ${KA9Q_RADIO_COMMIT_CHECK-yes} ${KA9Q_WEB_EABLED-yes} build_ka9q_radio ${KA9Q_RADIO_LIBS_NEEDED// /,} ${KA9Q_RADIO_GIT_URL-https://github.com/ka9q/ka9q-radio.git} ${KA9Q_WEB_COMMIT-1ee42250a2d4ce42d53c9ccdca81a73301f6a9ed}" + "ft8_lib ${KA9Q_FT8_COMMIT_CHECK-yes} ${KA9Q_FT8_EABLED-yes} build_ka9q_ft8 NONE ${KA9Q_FT8_GIT_URL-https://github.com/ka9q/ft8_lib.git} ${KA9Q_FT8_COMMIT-66f0b5cd70d2435184b54b29459bb15214120a2c}" + "ftlib-pskreporter ${PSK_UPLOADER_COMMIT_CHECK-yes} ${PSK_UPLOADER_ENABLED-yes} build_psk_uploader NONE ${PSK_UPLOADER_GIT_URL-https://github.com/pjsg/ftlib-pskreporter.git} ${PSK_UPLOADER_COMMIT-9e6128bb8882df27f52e9fd7ab28b3888920e9c4}" + "onion ${ONION_COMMIT_CHECK-yes} ${ONION_ENABLED-yes} build_onion ${ONION_LIBS_NEEDED// /,} ${ONION_GIT_URL-https://github.com/davidmoreno/onion} ${ONION_COMMIT-de8ea938342b36c28024fd8393ebc27b8442a161}" + "ka9q-web ${KA9Q_WEB_COMMIT_CHECK-main} ${KA9Q_WEB_ENABLED-yes} build_ka9q_web NONE ${KA9Q_WEB_GIT_URL-https://github.com/scottnewell/ka9q-web} ${KA9Q_WEB_COMMIT-86a17668d017dfcbc3371f864cacec2eaa081e36}" +) + +### +function ka9q-services-setup() { + local rc + wd_logger 2 "Starting in ${PWD}" + + local index + for (( index=0; index < ${#GITHUB_PROJECTS_LIST[@]}; ++index)) ; do + local project_info="${GITHUB_PROJECTS_LIST[index]}" + wd_logger 2 "Setup project '${project_info}'" + if ! install_github_project ${project_info} ; then + wd_logger 1 "ERROR: 'install_dpkg_list ${project_info}' => $?" + exit 1 fi done - wd_logger 2 "All three ka9q services: radiod, web and ft, are setup. So finished in $PWD" + wd_logger 2 "Done and exiting" + + return 0 +} + +### +function ka9q-setup() { + wd_logger 2 "Starting in ${PWD}" - ka9q-psk-reporter-setup + local active_receivers + get_list_of_active_real_receivers "active_receivers" + if ! [[ "${active_receivers}" =~ KA9Q ]]; then + wd_logger 1 "There are no KA9Q receivers in the conf file, so skip KA9Q setup" + return 0 + fi + wd_logger 2 "There are KA9Q receivers in the conf file, so set up KA9Q" + + ka9q-services-setup rc=$? if [[ ${rc} -ne 0 ]]; then - wd_logger 1 "ERROR: ka9q-psk-reporter-setup() => ${rc}" - save_rc=${rc} + wd_logger 1 "ERROR: ka9q-services-setup() => ${rc}" else - wd_logger 2 "ka9q-psk-reporter-setup() is setup" + wd_logger 2 "All ka9q services are installed" fi - return ${save_rc} + return ${rc} } -ka9q_setup +ka9q-setup diff --git a/wd_setup.sh b/wd_setup.sh index 9813953..b022395 100755 --- a/wd_setup.sh +++ b/wd_setup.sh @@ -485,11 +485,36 @@ function find_wsjtx_commands() done if [[ -z "${WSPRD_CMD-}" ]]; then wd_logger 1 "ERROR: couldn't find WSPRD_CMD" - exit 1 + local rc + sudo apt install wsjtx -y + rc=$? + if [[ ${rc} -ne 0 ]]; then + wd_logger 1 "Couldn't install wsprd: 'sudo apt install wsjtx -y' => ${rc}" + exit 1 + fi + local dpkg_wsprd_file_name="/usr/bin/wsprd" + if [[ ! -x ${dpkg_wsprd_file_name} ]]; then + wd_logger 1 "ERROR: after ' sudo apt install wsjtx -y' failed to find ${dpkg_wsprd_file_name}" + exit 1 + fi + cp ${dpkg_wsprd_file_name} bin/ + rc=$? + if [[ ${rc} -ne 0 ]]; then + wd_logger 1 "Couldn't 'cp ${dpkg_wsprd_file_name} bin/' => ${rc}" + exit 1 + fi + WSPRD_CMD=$(realpath bin/wsprd) + wd_logger 1 "Installed missing bin/wspsrd from the 'wsjtx' package" fi if [[ -z "${WSPRD_SPREADING_CMD-}" ]]; then - wd_logger 1 "ERROR: couldn't find WSPRD_SPREADING_CMD" - exit 1 + if grep -q "Ubuntu 20" /etc/os-release ; then + wd_logger 1 "On Ubuntu 20 installting bin/wsprd as wsprd.spread.ubuntu.20.x86" + cp bin/wsprd bin/wsprd.spread.ubuntu.20.x86 + WSPRD_SPREADING_CMD=$(realpath bin/wsprd.spread.ubuntu.20.x86) + else + wd_logger 1 "ERROR: couldn't find WSPRD_SPREADING_CMD" + exit 1 + fi fi if [[ -z "${JT9_CMD-}" ]]; then wd_logger 1 "ERROR: couldn't find JT9_CMD" diff --git a/wsprdaemon.sh b/wsprdaemon.sh index 952557f..1e7fb98 100755 --- a/wsprdaemon.sh +++ b/wsprdaemon.sh @@ -61,7 +61,8 @@ shopt -s -o nounset ### bash stops with error if undeclared variable is #declare VERSION=3.2.0 ### Add all weprd and jt9 binaries. Installs on Pi 5 #declare VERSION=3.2.1 ### Increment version number so wspr.rocks will report which WD sites have been upgraded #declare VERSION=3.2.2 ### Adds ka9q-web and FT4/8 reporting -declare VERSION=3.2.3 ### Merge 3.2.0 branch into master, a second time +#declare VERSION=3.2.3 ### Merge 3.2.0 branch into master, a second time +VERSION=$(git describe --tags --abbrev=0)-$(git rev-list --count HEAD) if [[ $USER == "root" ]]; then echo "ERROR: This command '$0' should NOT be run as user 'root' or non-root users will experience file permissions problems"