#!/bin/sh
# rpcd object exposing srunc to LuCI / ubus.
#
# Methods:
#   status   {"section": "<name>"}  -> {"online":bool, "username":str|null,
#                                       "ip":str|null,
#                                       "details": null | {plan, user_mac, sum_bytes, sum_seconds, online_device_total, keepalive_time, ...}}
#            `details` is populated only when the configured portal host has a
#            verified rad_user_info schema (currently auth4.tsinghua.edu.cn).
#   login    {}                     -> {"ok":bool}        # restarts the procd service
#   logout   {}                     -> {"ok":bool}        # stops the procd service
#   restart  {}                     -> {"ok":bool}
#   profiles {}                     -> {"profiles":[{"id","label","host","ac_id"}, ...]}
#   discover {}                     -> {"gateway":str, "host":str|null, "ac_id":str|null}
#   service_status {}               -> {"running":bool}
#
# `status` reads `/var/run/srunc/<section>.toml` (rendered by the init script
# when the daemon is running); falls back to offline if absent. Action methods
# delegate to /etc/init.d/srunc so the full "render UCI -> TOML -> spawn"
# pipeline runs in one place. `profiles` shells out to the binary so the
# registry stays single-sourced in Rust.

. /usr/share/libubox/jshn.sh

PROG=/usr/sbin/srunc
RUNDIR=/var/run/srunc
INIT=/etc/init.d/srunc

reply_offline() {
	json_init
	json_add_boolean online 0
	json_dump
}

reply_ok() {
	json_init
	json_add_boolean ok 1
	json_dump
}

reply_fail() {
	json_init
	json_add_boolean ok 0
	[ -n "$1" ] && json_add_string error "$1"
	json_dump
}

case "$1" in
list)
	json_init
	json_add_object "status";  json_add_string section "";  json_close_object
	json_add_object "log";     json_add_int lines 0; json_close_object
	json_add_object "login";   json_close_object
	json_add_object "logout";  json_close_object
	json_add_object "restart";  json_close_object
	json_add_object "profiles"; json_close_object
	json_add_object "discover"; json_close_object
	json_add_object "service_status"; json_close_object
	json_dump
	;;

call)
	# Args arrive as one JSON object on stdin.
	json_load "$(cat)"
	json_get_var section section
	section="${section:-default}"
	cfg="$RUNDIR/$section.toml"

	case "$2" in
	status)
		if [ -f "$cfg" ]; then
			out=$("$PROG" -c "$cfg" status --json 2>/dev/null) || out=""
			if [ -n "$out" ]; then
				printf '%s' "$out"
			else
				reply_offline
			fi
		else
			reply_offline
		fi
		;;
	login)
		if "$INIT" restart >/dev/null 2>&1; then
			reply_ok
		else
			reply_fail "init.d restart failed"
		fi
		;;
	logout)
		# Best-effort portal logout, then stop the keepalive daemon.
		if [ -f "$cfg" ]; then
			"$PROG" -c "$cfg" logout >/dev/null 2>&1 || true
		fi
		if "$INIT" stop >/dev/null 2>&1; then
			reply_ok
		else
			reply_fail "init.d stop failed"
		fi
		;;
	restart)
		if "$INIT" restart >/dev/null 2>&1; then
			reply_ok
		else
			reply_fail "init.d restart failed"
		fi
		;;
	log)
		# Recent srunc messages from the system log. Read-only; covers both
		# procd-captured daemon output and the init.d `logger -t srunc` lines.
		json_get_var lines lines
		lines="${lines:-200}"
		out=$(logread -e srunc 2>/dev/null | tail -n "$lines")
		json_init
		json_add_string log "$out"
		json_dump
		;;
	profiles)
		# Defer to the binary so the registry lives in exactly one place.
		# Output is already an array of {id,label,host,ac_id}; wrap it in
		# the {profiles: [...]} envelope LuCI expects from an ubus method.
		out=$("$PROG" profiles list --json 2>/dev/null) || out="[]"
		printf '{"profiles":%s}\n' "$out"
		;;
	discover)
		# Probe the default gateway. Output is already JSON-shaped by the
		# binary ({gateway, host, ac_id}); pass it through verbatim. On
		# error emit an explicit failure object so the Settings view can
		# surface "no captive redirect found" as a toast.
		if out=$("$PROG" --json discover 2>&1); then
			printf '%s\n' "$out"
		else
			reply_fail "$out"
		fi
		;;
	service_status)
		# Is the daemon actually running? `pgrep -x` matches the exact
		# basename (so a stray `srunc-foo` doesn't false-positive) and is
		# present on every OpenWrt build. We don't try to enumerate
		# instances here — the Log view just needs running yes/no.
		if pgrep -x srunc >/dev/null 2>&1; then
			printf '{"running":true}\n'
		else
			printf '{"running":false}\n'
		fi
		;;
	*)
		reply_fail "unknown method"
		;;
	esac
	;;
esac
