#!/bin/sh
#
# Copyright (C) 2026 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 pushes network.<iface>.multipath_weight into mqvpn's wrtt
# (Weighted RTT) or wrr (Weighted Round Robin) scheduler via the control
# API. Both schedulers read the same per-path weight (mqvpn_path_desc_t.weight
# / mqvpn_client_set_path_weight); they only differ in how they use it.
# multipath_weight is set the same way as for the MPTCP weight schedulers
# (e.g. luci.mptcp's set_interface_settings rpcd call), so this just keeps
# mqvpn in sync with whatever weight was last pushed through that API.

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

if [ "$(uci -q get mqvpn.settings.enable)" != "1" ]; then
	exit 0
fi

if [ -z "$OMR_TRACKER_DEVICE" ] || [ -z "$OMR_TRACKER_INTERFACE" ]; then
	exit 0
fi

mqvpn_scheduler="$(uci -q get mqvpn.multipath.scheduler)"
if [ "$mqvpn_scheduler" != "wrtt" ] && [ "$mqvpn_scheduler" != "wrr" ]; then
	exit 0
fi

# Don't manage VPN interfaces
if [ "$(uci -q get openmptcprouter.$OMR_TRACKER_INTERFACE.vpn)" = "1" ]; then
	exit 0
fi

if [ "$(pgrep -f mqvpn)" = "" ]; then
	exit 0
fi

multipath_config=$(uci -q get "openmptcprouter.$OMR_TRACKER_INTERFACE.multipath")
[ -z "$multipath_config" ] && multipath_config=$(uci -q get "network.$OMR_TRACKER_INTERFACE.multipath" || echo "off")

if [ "$multipath_config" != "on" ] && [ "$multipath_config" != "master" ] && [ "$multipath_config" != "backup" ]; then
	exit 0
fi

# Unset is 100, as for the MPTCP weight schedulers: the Weight field of the
# MPTCP page leaves it unset when emptied. mqvpn's own default is 1, and the
# old weight stayed on the path until mqvpn restarted.
weight="$(uci -q get "network.$OMR_TRACKER_INTERFACE.multipath_weight")"
weight="${weight:-100}"
# The VPS model's weight, kept in /var/state by omr-weight-sync while it
# runs with decision weights on, is the one in the router's map: use that
_mw="$(uci -q -P /var/state get openmptcprouter.$OMR_TRACKER_INTERFACE.decision_weight)"
case "$_mw" in
	''|*[!0-9]*) _mw="" ;;
esac
if [ -n "$_mw" ] && [ -n "$(uci -q get omr-metrics.settings)" ] && \
   [ "$(uci -q get omr-metrics.settings.enable_weight_sync)" != "0" ] && \
   [ "$(uci -q get omr-metrics.settings.enable_decision_weights)" != "0" ]; then
	weight="$_mw"
fi

# openmptcprouter.<iface>.mqvpn_weight is the weight last applied to this
# path, as "<mqvpn pid>:<weight>". mqvpn keeps per-path weights in RAM
# only, so the cache is runtime state too: /var/state is empty after a
# reboot, a restarted mqvpn has another pid, and 005-mqvpn-path clears it
# whenever the path is removed. Either way the weight is applied again,
# even if multipath_weight itself never changed. (It used to be
# network.<iface>.weight, committed to flash: it outlived the mqvpn that
# had the weight, and that option is the balancing weight of the route.)
mqvpn_pid="$(pidof mqvpn 2>/dev/null)"
mqvpn_pid="${mqvpn_pid%% *}"
current_weight="$(omr_state_get "openmptcprouter.$OMR_TRACKER_INTERFACE.mqvpn_weight")"

# mqvpn_weight_failed is the weight that could not be set: a down WAN has no
# path, and the weight is tried again on every run until it has one. Logged
# once, not every minute while it stays down.
if [ "${mqvpn_pid}:${weight}" != "$current_weight" ]; then
	failed_weight="$(omr_state_get "openmptcprouter.$OMR_TRACKER_INTERFACE.mqvpn_weight_failed")"
	[ "$failed_weight" = "${mqvpn_pid}:${weight}" ] || _log "mqvpn: set weight $OMR_TRACKER_DEVICE ($OMR_TRACKER_INTERFACE) -> $weight"
	if mqvpn-path weight "$OMR_TRACKER_DEVICE" "$weight" >/dev/null 2>&1; then
		omr_state_set openmptcprouter "$OMR_TRACKER_INTERFACE" mqvpn_weight "${mqvpn_pid}:${weight}"
		[ -n "$failed_weight" ] && omr_state_del openmptcprouter "$OMR_TRACKER_INTERFACE" mqvpn_weight_failed
	elif [ "$failed_weight" != "${mqvpn_pid}:${weight}" ]; then
		_log "mqvpn: failed to set weight $OMR_TRACKER_DEVICE ($OMR_TRACKER_INTERFACE) -> $weight"
		omr_state_set openmptcprouter "$OMR_TRACKER_INTERFACE" mqvpn_weight_failed "${mqvpn_pid}:${weight}"
	fi
fi

exit 0
