#!/bin/sh /etc/rc.common
# /etc/init.d/byedpi — procd supervisor for ByeDPI (ciadpi) desync SOCKS proxies.
#
# One supervised `ciadpi` process per ENABLED `config instance` in
# /etc/config/byedpi. Each instance is a local SOCKS5 desync proxy bound to
# 127.0.0.1:<port>; a Shater egress of type='byedpi' with the matching `port`
# routes traffic to it (shaterd emits a SOCKS5 outbound to that port). ciadpi
# desyncs the connection and goes DIRECT to the target — no tunnel.
#
# Design:
#   * INERT by default: the shipped instance has enabled='0', and config_foreach
#     starts nothing unless an instance is explicitly enabled. Installing this
#     package can never, by itself, open a listener or affect connectivity.
#   * FOREGROUND: ciadpi stays in the foreground unless -D/--daemon is given (we
#     never pass it), so procd supervises the real process. respawn on crash.
#   * Instances are named after their UCI section, so `reload` diffs per-section
#     and restarts only the instances whose config actually changed.
#   * busybox ash only — no bashisms.

USE_PROCD=1
START=90          # before shater (START=99): the SOCKS egress should be up
STOP=11           # after shater (STOP=10) — higher STOP runs LATER on shutdown,
                  # so the desync proxy outlives the data plane it serves.

PROG=/usr/bin/ciadpi
CONF=byedpi

# Validate one `instance` section. Datatypes per openwrt-uci:
#   enabled : bool  (default 0 — inert)
#   port    : port  (default 1080 — matches shater's byedpi egress default)
#   args    : free-form desync flag string (passed verbatim to ciadpi)
validate_instance_section() {
	uci_load_validate "$CONF" instance "$1" "$2" \
		'enabled:bool:0' \
		'port:port:1080' \
		'args:string:'
}

start_instance() {
	# $1 = section name, $2 = validation return code
	local cfg="$1"
	[ "$2" = 0 ] || { echo "byedpi: validation failed for '$cfg'"; return 1; }
	[ "$enabled" -eq 1 ] || return 0

	# Never claim to run without the binary (half-removed/failed upgrade must
	# degrade to "off", not to a phantom respawn loop).
	[ -x "$PROG" ] || { echo "byedpi: $PROG missing, skipping '$cfg'"; return 1; }

	procd_open_instance "$cfg"
	# Bind loopback only: this proxy is reachable solely by the local engine.
	procd_set_param command "$PROG" -i 127.0.0.1 -p "$port"
	# Desync flag list. Unquoted on purpose: word-split $args into separate argv
	# tokens (e.g. "--disorder 1 --auto=torst --tlsrec 1+s" -> 5 arguments).
	# shellcheck disable=SC2086
	[ -n "$args" ] && procd_append_param command $args

	procd_set_param respawn
	# Restart this instance when its config changes (checksum-watched).
	procd_set_param file /etc/config/$CONF
	procd_set_param stdout 1
	procd_set_param stderr 1
	procd_close_instance
}

start_service() {
	config_load "$CONF"
	config_foreach validate_instance_section instance start_instance
}

reload_service() {
	start_service
}

service_triggers() {
	# Reload (not full restart) when /etc/config/byedpi changes via a
	# config.change event (LuCI Save&Apply / `reload_config`).
	procd_add_reload_trigger "$CONF"
	procd_add_validation validate_instance_section
}
