#!/bin/bash
#
# Copyright (C) 2018-2023 Ycarus (Yannick Chabanois) <ycarus@zugaina.org> for OpenMPTCProuter
#
# This is free software, licensed under the GNU General Public License v2.
# See /LICENSE for more information.
#
# This script launch a speedtest if the option is enabled on the interface

. "${OMR_LIB_DIR:-/usr/share/omr/lib}/omr-state.sh"

{ [ "$OMR_TRACKER_STATUS" = "ERROR" ] || [ -z "$OMR_TRACKER_INTERFACE" ]; } && exit 0
# Off unless enabled on the interface: test that first. The interface state
# (ifstatus, i.e. a shell, two ubus and a jsonfilter) and the pgrep below
# used to run on every cycle of every WAN to find out there was nothing to do.
[ "$(uci -q get openmptcprouter.${OMR_TRACKER_INTERFACE}.testspeed)" = "1" ] || exit 0
interface_up=$(ubus call network.interface."$OMR_TRACKER_INTERFACE" status 2>/dev/null | jsonfilter -q -e '@["up"]')
[ "$interface_up" != "true" ] && exit 0

# testspeed_lc marks the automatic speedtest as done for this interface. It
# stays in the persistent config, unlike the runtime values in /var/state:
# kept there, it was gone after each reboot and the 6 tests ran again on
# every boot on each interface with testspeed enabled.
# A test without a result leaves it unset: the 3 to 6 transfers (each a VPS
# login and up to 30 s, with SQM stopped) then ran again on every cycle, so
# the time of the last attempt is kept, in the runtime state, and the test
# is tried again an hour later.
# The results are staged apart from /tmp/.uci, and committed while nothing
# else is pending there for the package: libuci always reads /tmp/.uci too,
# even with -t, so a commit also wrote other processes' pending changes.
# Results that have to wait are committed on a later cycle.
_speedtest_uci_dir="/tmp/.uci-omr-speedtest-${OMR_TRACKER_INTERFACE}"
_speedtest_uci() {
	uci -q -t "$_speedtest_uci_dir" "$@"
}
_speedtest_commit() {
	local _pkg _left=""
	# the testspeed_lc marker last
	for _pkg in sqm network openmptcprouter; do
		[ -s "$_speedtest_uci_dir/$_pkg" ] || continue
		if [ -n "$(uci -q changes "$_pkg")" ]; then
			_left=1
			continue
		fi
		_speedtest_uci commit "$_pkg"
	done
	[ -n "$_left" ] || rm -rf "$_speedtest_uci_dir"
}
if [ -d "$_speedtest_uci_dir" ]; then
	_speedtest_commit
	exit 0
fi

printf -v _speedtest_now '%(%s)T' -1
_speedtest_tried="$(omr_state_get openmptcprouter.${OMR_TRACKER_INTERFACE}.testspeed_tried)"
case "$_speedtest_tried" in
	''|*[!0-9]*) _speedtest_tried=0 ;;
esac
if [ -n "$OMR_TRACKER_INTERFACE" ] && [ -n "$OMR_TRACKER_DEVICE" ] && [ "$(pgrep -f omr-test-speed-server)" = "" ] && [ -z "$(uci -q get openmptcprouter.${OMR_TRACKER_INTERFACE}.testspeed_lc)" ] && [ $((_speedtest_now - _speedtest_tried)) -ge 3600 ]; then
	speedtest_bin="/bin/omr-test-speed-server"
	[ -x "$speedtest_bin" ] || speedtest_bin="omr-test-speed-server"
	_speedtest_done=""
	launch_speedtest() {
		local server=$1
		[ "$(omr_state_get openmptcprouter.${server}.current)" != "1" ] && return
		omr_state_set openmptcprouter "$OMR_TRACKER_INTERFACE" testspeed_tried "$_speedtest_now"
		download_speed=$("$speedtest_bin" ${server} ${OMR_TRACKER_DEVICE} fasttest)
		download_speed2=$("$speedtest_bin" ${server} ${OMR_TRACKER_DEVICE} fasttest)
		download_speed3=$("$speedtest_bin" ${server} ${OMR_TRACKER_DEVICE} fasttest)
		[ "$download_speed2" -gt "$download_speed" ] && download_speed=${download_speed2}
		[ "$download_speed3" -gt "$download_speed" ] && download_speed=${download_speed3}
		download_speed=$((download_speed*8/1000))
		if [ -n "$download_speed" ] && [ "$download_speed" != "0" ]; then
				upload_speed=$("$speedtest_bin" ${server} ${OMR_TRACKER_DEVICE} fasttest upload)
				upload_speed2=$("$speedtest_bin" ${server} ${OMR_TRACKER_DEVICE} fasttest upload)
				upload_speed3=$("$speedtest_bin" ${server} ${OMR_TRACKER_DEVICE} fasttest upload)
			[ "$upload_speed2" -gt "$upload_speed" ] && upload_speed=${upload_speed2}
			[ "$upload_speed3" -gt "$upload_speed" ] && upload_speed=${upload_speed3}

			# Set Download speed settings
			if [ "$(uci -q get sqm.${OMR_TRACKER_INTERFACE}.autorate)" = "1" ]; then
				_speedtest_uci set sqm.${OMR_TRACKER_INTERFACE}.download=$((download_speed*65/100))
				_speedtest_uci set sqm.${OMR_TRACKER_INTERFACE}.max_download=${download_speed}
				_speedtest_uci set sqm.${OMR_TRACKER_INTERFACE}.min_download=$((download_speed*10/100))
			else
				_speedtest_uci set sqm.${OMR_TRACKER_INTERFACE}.download=$((download_speed*95/100))
			fi
			_log "Calculated ${OMR_TRACKER_INTERFACE} download speed: ${download_speed}"
			_speedtest_uci set network.${OMR_TRACKER_INTERFACE}.downloadspeed=${download_speed}

			# Set Upload speed settings
			upload_speed=$((upload_speed*8/1000))
			if [ -n "$upload_speed" ] && [ "$upload_speed" != "0" ]; then
				if [ "$(uci -q get sqm.${OMR_TRACKER_INTERFACE}.autorate)" = "1" ]; then
					_speedtest_uci set sqm.${OMR_TRACKER_INTERFACE}.upload=$((upload_speed*65/100))
					_speedtest_uci set sqm.${OMR_TRACKER_INTERFACE}.max_upload=${upload_speed}
					_speedtest_uci set sqm.${OMR_TRACKER_INTERFACE}.min_upload=$((upload_speed*10/100))
				else
					_speedtest_uci set sqm.${OMR_TRACKER_INTERFACE}.upload=$((upload_speed*95/100))
				fi
				_log "Calculated ${OMR_TRACKER_INTERFACE} upload speed: ${upload_speed}"
				_speedtest_uci set network.${OMR_TRACKER_INTERFACE}.uploadspeed=${upload_speed}
				_speedtest_uci set openmptcprouter.${OMR_TRACKER_INTERFACE}.testspeed_lc=$(date +"%s")
				_speedtest_done=1
			fi
		fi
	}
	config_load openmptcprouter
	config_foreach launch_speedtest server
	# what a test without an upload result staged is dropped
	if [ -n "$_speedtest_done" ]; then
		_speedtest_commit
	else
		rm -rf "$_speedtest_uci_dir"
	fi

	sleep 5
fi

exit 0
