2024-03-30 21:03:17 +00:00
|
|
|
# shellcheck shell=bash
|
|
|
|
|
2024-03-30 19:44:17 +00:00
|
|
|
export ZERO="$0"
|
|
|
|
HELP="$ZERO: tracker [-1] [-v [-v ...]] [q [-q ...]]
|
|
|
|
-1 run once and exit
|
|
|
|
-v increase verbosity (default >= warn)
|
|
|
|
-q decrease verbosity
|
|
|
|
"
|
2024-03-30 21:03:17 +00:00
|
|
|
trap 'kill -15 $$' INT
|
2024-03-30 19:44:17 +00:00
|
|
|
|
|
|
|
trace() { (( LOG_LEVEL > 2 )) && (exec 1>&2; builtin echo "$@"|grep .||true); }
|
|
|
|
debug() { (( LOG_LEVEL > 1 )) && (exec 1>&2; builtin echo "$@"|grep .||true); }
|
|
|
|
info() { (( LOG_LEVEL > 0 )) && (exec 1>&2; builtin echo "$@"|grep .||true); }
|
|
|
|
warn() { (( LOG_LEVEL > -1 )) && (exec 1>&2; builtin echo "$@"|grep .||true); }
|
|
|
|
error() { (( LOG_LEVEL > -2 )) && (exec 1>&2; builtin echo "$@"|grep .||true); }
|
|
|
|
fatal() { (exec 1>&2; builtin echo "$@"|grep .||true); exit 4; }
|
|
|
|
log() { info "$@"; }
|
|
|
|
|
2024-03-30 21:03:17 +00:00
|
|
|
unbuf() { SCRIPT="$1"; shift ; stdbuf -oL -eL bash -c "$SCRIPT" - "$@" ; }
|
|
|
|
|
2024-03-30 19:44:17 +00:00
|
|
|
start() {
|
|
|
|
if ! options="$(getopt vq1 -- "$@")";then
|
|
|
|
fatal "$HELP"
|
|
|
|
fi
|
|
|
|
|
|
|
|
eval set "$options"
|
|
|
|
|
|
|
|
while [ $# -gt 0 ];do
|
|
|
|
case "$1" in
|
2024-03-30 21:03:17 +00:00
|
|
|
-1) ONCE=1 ;;
|
|
|
|
-h) info "$HELP"; exit 0 ;;
|
|
|
|
-v) LOG_LEVEL=$(( LOG_LEVEL + 1 )) ;;
|
2024-03-30 19:44:17 +00:00
|
|
|
-q) LOG_LEVEL=$(( LOG_LEVEL - 1 )) ;;
|
|
|
|
--) shift;break;; # we're _explicitly_ done with options
|
2024-03-30 21:03:17 +00:00
|
|
|
-*) error "invalid option $1"; fatal "$HELP" ;;
|
2024-03-30 19:44:17 +00:00
|
|
|
*) break;; # we're done with options.
|
|
|
|
esac
|
|
|
|
shift
|
|
|
|
done
|
|
|
|
|
2024-03-30 21:03:17 +00:00
|
|
|
if [ "$VALIDATION" ];then
|
2024-03-30 19:44:17 +00:00
|
|
|
# fix up the validation regex to not search.
|
|
|
|
VALIDATION="${VALIDATION#^}"
|
|
|
|
VALIDATION="${VALIDATION%'$'}"
|
|
|
|
VALIDATION='^'"$VALIDATION"'$'
|
|
|
|
fi
|
|
|
|
|
|
|
|
info "Running with LOG_LEVEL=$LOG_LEVEL"
|
|
|
|
|
|
|
|
debug " VALIDATION: $VALIDATION"
|
|
|
|
debug " RATE_LIMIT: $RATE_LIMIT"
|
|
|
|
debug "POLL_INTERVAL: $POLL_INTERVAL"
|
|
|
|
debug " watch_cmd: $watch_cmd"
|
|
|
|
|
2024-03-30 21:03:17 +00:00
|
|
|
if [ "$(echo "$POLL_INTERVAL < $RATE_LIMIT"|bc)" = 1 ];then
|
2024-03-30 19:44:17 +00:00
|
|
|
warn "POLL_INTERVAL cannot be less than RATE_LIMIT."
|
|
|
|
info "increasing POLL_INTERVAL to $RATE_LIMIT."
|
|
|
|
POLL_INTERVAL=$RATE_LIMIT
|
|
|
|
fi
|
|
|
|
|
2024-03-30 21:03:17 +00:00
|
|
|
while true;do
|
|
|
|
_poll || exit $?
|
|
|
|
(( ONCE )) && exit 0
|
|
|
|
|
|
|
|
$watch_cmd | while sleep $RATE_LIMIT;do
|
|
|
|
# read with a maximum of the poll interval minus the previous rate limit.
|
|
|
|
# rounding _up_ to the nearest second. (bc floors when scale is unset.)
|
|
|
|
if read -r -t "$( echo "$POLL_INTERVAL - $RATE_LIMIT + .5 " | bc )";then
|
|
|
|
debug "received poll. removing other poll requests."
|
|
|
|
else
|
|
|
|
debug "reached the polling interval. forcing poll."
|
|
|
|
fi
|
|
|
|
N=0
|
|
|
|
while read -t 0;do read -r; N=$((N + 1));done
|
|
|
|
debug "removed $N extra events"
|
|
|
|
_poll
|
|
|
|
debug "sleeping for $RATE_LIMIT"
|
|
|
|
done
|
|
|
|
warn "tracker died. restarting after $RATE_LIMIT seconds."
|
|
|
|
sleep $RATE_LIMIT
|
|
|
|
done | unbuf "$_filter"
|
2024-03-30 19:44:17 +00:00
|
|
|
info "bye"
|
|
|
|
}
|
|
|
|
|
|
|
|
_poll() {
|
|
|
|
NEWVAL="$(poll | head -1)"
|
|
|
|
local skipped=0
|
|
|
|
echo "$NEWVAL" | while read -r LINE;do
|
|
|
|
(( skipped )) && info "$LINE"
|
|
|
|
skipped=1
|
|
|
|
done
|
|
|
|
|
|
|
|
local failed=0
|
2024-03-30 21:03:17 +00:00
|
|
|
if [ "$JQ_VALIDATION" ];then
|
2024-03-30 19:44:17 +00:00
|
|
|
echo "$NEWVAL" | jq -e "$JQ_VALIDATION" > /dev/null || failed=1
|
|
|
|
fi
|
2024-03-30 21:03:17 +00:00
|
|
|
if [ "$VALIDATION" ];then
|
2024-03-30 19:44:17 +00:00
|
|
|
echo "$NEWVAL" | grep -qE "$VALIDATION" || failed=1
|
|
|
|
fi
|
|
|
|
if (( failed ));then
|
|
|
|
warn "$NEWVAL failed validation"
|
|
|
|
else
|
|
|
|
echo "$NEWVAL"
|
|
|
|
fi
|
|
|
|
}
|
|
|
|
|
|
|
|
# MODULE OPTIONS
|
|
|
|
|
|
|
|
RATE_LIMIT=.1
|
|
|
|
rate_limit() {
|
|
|
|
RATE_LIMIT=$1
|
|
|
|
}
|
|
|
|
|
|
|
|
POLL_INTERVAL=60
|
|
|
|
poll_interval() {
|
|
|
|
POLL_INTERVAL=$1
|
|
|
|
}
|
|
|
|
|
2024-03-30 21:03:17 +00:00
|
|
|
_filter="uniq"
|
2024-03-30 19:44:17 +00:00
|
|
|
filter() {
|
|
|
|
_filter="$(printf " %q" "$@")"
|
|
|
|
}
|
|
|
|
|
|
|
|
# VALIDATORS
|
|
|
|
|
|
|
|
VALIDATION=.
|
|
|
|
output_integer() {
|
|
|
|
VALIDATION='^-?[0-9]+$'
|
|
|
|
}
|
|
|
|
|
|
|
|
output_boolean() {
|
|
|
|
VALIDATION='^true|false$'
|
|
|
|
}
|
|
|
|
|
|
|
|
output_string() {
|
|
|
|
VALIDATION="${1-.*}"
|
|
|
|
}
|
|
|
|
|
|
|
|
output_json() {
|
|
|
|
JQ_VALIDATION="${1-.}"
|
|
|
|
}
|
|
|
|
|
|
|
|
# EVENT HANDLERS
|
|
|
|
|
|
|
|
# each event source needs to emit a single _EMPTY_ line per event.
|
|
|
|
# poll will be called for each line.
|
|
|
|
on_volume() { on _on_volume; }
|
|
|
|
_on_volume() {
|
|
|
|
pactl subscribe | while read -r ;do
|
|
|
|
case "$REPLY" in
|
|
|
|
*change*) echo;;
|
|
|
|
esac
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
on_sway() { on _on_sway; }
|
|
|
|
_on_sway() {
|
|
|
|
swaymsg -t subscribe -m '[ "workspace", "window" ]' |
|
|
|
|
jq --unbuffered -c . |
|
|
|
|
while read -r;do
|
|
|
|
echo
|
|
|
|
done
|
|
|
|
}
|
|
|
|
|
|
|
|
on() { watch_cmd="$1"; }
|