#!/bin/sh
# starlink.sh - Starlink dish health via gRPC.
#
# Config:
#   STARLINK_HOST    dish gRPC address (default: 192.168.100.1:9200)
#   GRPCURL          path to grpcurl binary (default: searches PATH)
#
# Public API:
#   starlink_status    echo 'lat_ms dl_bps obstructed outage'; exit 1 if unreachable
#   starlink_online    exit 0 if dish is reachable and latency > 0

LIB_DIR="${LIB_DIR:-/usr/lib/busrouter}"
: "${STARLINK_HOST:=192.168.100.1:9200}"

# Locate grpcurl: honour explicit GRPCURL env var, then PATH.
_grpcurl_bin() {
	if [ -n "${GRPCURL:-}" ]; then
		[ -x "$GRPCURL" ] && { echo "$GRPCURL"; return 0; }
		return 1
	fi
	command -v grpcurl 2>/dev/null || return 1
}

# Parse grpcurl JSON output -> 'lat_ms dl_bps obstructed outage'.
# Handles camelCase field names returned by Starlink gRPC reflection.
_starlink_parse() {
	awk '
		BEGIN { lat=0; dl=0; obs=0; outage=0; in_outage=0; frac=0 }
		/popPingLatencyMs/         { match($0, /[0-9]+\.?[0-9]*/); lat  = substr($0, RSTART, RLENGTH)+0 }
		/downlinkThroughputBps/    { match($0, /[0-9]+\.?[0-9]*/); dl   = substr($0, RSTART, RLENGTH)+0 }
		/currentlyObstructed.*true/ { obs = 1 }
		/fractionObstructed/       { match($0, /[0-9]+\.?[0-9]*/); frac = substr($0, RSTART, RLENGTH)+0; if (frac > 0.01) obs = 1 }
		/"outage".*\{/            { in_outage = 1 }
		in_outage && /"cause".*:.*"[A-Z]/ { outage = 1 }
		END { printf "%d %.0f %d %d\n", lat, dl, obs+0, outage+0 }
	'
}

# Run the gRPC status call and emit 'lat_ms dl_bps obstructed outage'.
# Returns exit 1 if grpcurl is absent or the dish is unreachable.
starlink_status() {
	local bin
	bin=$(_grpcurl_bin) || { logger -t busrouter "starlink: grpcurl not found"; return 1; }
	local json
	json=$("$bin" -plaintext -d '{"getStatus":{}}' "$STARLINK_HOST" SpaceX.API.Device.Device/Handle 2>/dev/null)
	[ -n "$json" ] || { logger -t busrouter "starlink: no response from $STARLINK_HOST"; return 1; }
	local result
	result=$(echo "$json" | _starlink_parse)
	logger -t busrouter -p daemon.debug "starlink_status: $result"
	echo "$result"
}

# Exit 0 if the dish is reachable and reporting non-zero latency.
starlink_online() {
	local lat
	lat=$(starlink_status 2>/dev/null | awk '{print $1}') || return 1
	[ "${lat:-0}" -gt 0 ] 2>/dev/null
}
