#!/bin/bash /etc/rc.common
# Copyright (C) 2023-2024 muink

. "${IPKG_INSTROOT}/lib/functions.sh"
. "${IPKG_INSTROOT}/usr/share/libubox/jshn.sh"

START=99
USE_PROCD=1

EXTRA_COMMANDS="getinfo checkln symln setcron cleanup"
EXTRA_HELP=\
"	getinfo			Get releases/targets/archs list
	checkln			Check home path
	symln [home_url]	Make symlink to mount porint
	setcron [cron]		Add cron expression to crontabs
	cleanup [autorm]	Clean up invalid versions"

CONFIG_NAME='packagesync'
SCONFIG='config'
RELEASE='release'

MNTPKGS='/mnt/packagesync'
CRONTABS='/etc/crontabs/root'
SYNCEXE='/usr/libexec/packagesync/sync'
PIDFILE='/var/run/packagesync.pid'
DEF_HOMEURL="packagesync"
DEF_HOMEPATH="/www/$DEF_HOMEURL"
RELEASES_LIST="/var/packagesync/releaseslist"
TARGETS_LIST="/var/packagesync/targetslist"
PKGARCHS_LIST="/var/packagesync/pkgarchslist"
RESULTPATH='/var/packagesync/results'
# url path
DOWNLOAD_URL="https://downloads.openwrt.org"
URLHREF_RELEASES='releases'
URLHREF_SNAPSHOTS='snapshots'
URLHREF_PACKAGES_PREFIX='packages-' # packages-22.03
URLHREF_VERS_PACKAGES='packages'
URLHREF_VERS_TARGETS='targets'

config_load $CONFIG_NAME



# define global var: GLOBAL_*
define_global() {
	[ "$2" == "0" ] || { >&2 echo "$(basename $0): section $1 validation failed"; return 1; }

	local error=0
	local v ucivv="download_url rsync_url home_url bwlimit proxy_enabled proxy_protocol proxy_server"
	for v in $ucivv; do
		[ -z "$(config_get $1 $v)" ] && grep -qEv "^(download_url|rsync_url|proxy_protocol|proxy_server)$" <<< "$v" && {
			>&2 echo "$(basename $0): section $1 option $v cannot be empty"
			let error++
		}
		config_get GLOBAL_$v $1 $v
	done

	[ "$error" -gt 0 ] && return 1 || return 0
}

validate_section_config() {
	uci_load_validate "$CONFIG_NAME" "$SCONFIG" "$1" "$2" \
		'download_url:string' \
		'rsync_url:string' \
		'home_url:string' \
		'bwlimit:uinteger:8000' \
		'auto_exec:bool:1' \
		'cron_expression:string' \
		'proxy_enabled:bool:0' \
		'proxy_protocol:string:socks5' \
		'proxy_server:string'
}

validate_section_release() {
	uci_load_validate $CONFIG_NAME $RELEASE "$1" "$2" \
		'enabled:bool:0' \
		'name:uciname' \
		'version:string' \
		'target:string' \
		'pkgarch:string' \
		'model:string' \
		'extra:bool:0'
}

gen_order() {
	[ "$2" == "0" ] || { >&2 echo "section $1 validation failed"; return 1; }
	[ "$enabled" == "0" ] && return 0

	json_init
	json_load "$orders"
	json_select orders
	json_add_object
	json_add_string name "$name"
	json_add_string version "$version"
	json_add_string target "$target"
	json_add_string arch "$pkgarch"
	json_add_string model "$model"
	json_add_boolean extra "$extra"
	json_close_object
	orders="$(json_dump)"
}

sync_instance() {
	[ -z "$1" ] && return 1

	procd_open_instance 'sync'
	procd_set_param command "$SYNCEXE" -o "$1"
	procd_append_param command -l "$bwlimit" -d "$homepath" ${ALL_PROXY:+-x $ALL_PROXY} \
		${GLOBAL_rsync_url:+--rsyncurl "$GLOBAL_rsync_url"}
	#procd_set_param respawn
	#procd_set_param stdout 1
	procd_set_param stderr 1
	procd_set_param user root
	procd_set_param pidfile "$PIDFILE"
	procd_close_instance
}

start_service() {
	# locked file check
	[ -n "$(cat "$PIDFILE" 2>/dev/null)" -a -n "$(ps|grep -E "^\s*$(cat "$PIDFILE" 2>/dev/null)")" ] && return 1
	# mount point check
	[ -n "$(df -hT|grep "$MNTPKGS")" ] || return 1

	validate_section_config "$SCONFIG" define_global || return $?
	local homepath bwlimit
	[ -n "$GLOBAL_home_url" ] && homepath="/www/$GLOBAL_home_url" || homepath="$DEF_HOMEPATH"
	[ -d "$homepath" ] || { >&2 echo -e "$CONFIG_NAME: The Home Path '$homepath' is invalid. please check the 'home_url'"; return 1; }
	bwlimit="$GLOBAL_bwlimit"
	[ "$GLOBAL_proxy_enabled" = "1" ] && {
		export ALL_PROXY=$GLOBAL_proxy_protocol://$GLOBAL_proxy_server
	}

	local orders='{ "orders": [] }'
	config_foreach validate_section_release $RELEASE gen_order

	sync_instance "$(jsonfilter -q -s "$orders" -e @.orders)"
	#$SYNCEXE -l|--bwlimit "$bwlimit" -d|--homedir "$homepath" -n|--name "x64_21_02_5" -s|--version "21.02.5" -t|--target "x86/64" -k|--arch "x86_64";
	#$SYNCEXE -l|--bwlimit "$bwlimit" -d|--homedir "$homepath" -n|--name "x64_22_03_2" -s|--version "22.03.2" -t|--target "x86/64" -k|--arch "x86_64";
	#$SYNCEXE -l|--bwlimit "$bwlimit" -d|--homedir "$homepath" -n|--name "ath79_21_02_5" -s|--version "21.02.5" -t|--target "ath79/nand" -k|--arch "mips_24kc";
	#$SYNCEXE -l|--bwlimit "$bwlimit" -d|--homedir "$homepath" -n|--name "ath79_22_03_2" -s|--version "22.03.2" -t|--target "ath79/nand" -k|--arch "mips_24kc";
    #
	#$SYNCEXE -l|--bwlimit "$bwlimit" -o|--orders '[ {"homedir": "$homepath", "name": "x64_21_02_5", "version": "21.02.5", "target": "x86/64", "arch": "x86_64"}, \
	#												{"homedir": "$homepath", "name": "x64_22_03_2", "version": "22.03.2", "target": "x86/64", "arch": "x86_64"}, \
	#												{"homedir": "$homepath", "name": "ath79_21_02_5", "version": "21.02.5", "target": "ath79/nand", "arch": "mips_24kc"}, \
	#												{"homedir": "$homepath", "name": "ath79_22_03_2", "version": "22.03.2", "target": "ath79/nand", "arch": "mips_24kc"} ]'
    #
	#$SYNCEXE -l|--bwlimit "$bwlimit" -d|--homedir "$homepath" -o|--orders '[ {"name": "x64_21_02_5", "version": "21.02.5", "target": "x86/64", "arch": "x86_64"}, \
	#																			{"name": "x64_22_03_2", "version": "22.03.2", "target": "x86/64", "arch": "x86_64"}, \
	#																			{"name": "ath79_21_02_5", "version": "21.02.5", "target": "ath79/nand", "arch": "mips_24kc"}, \
	#																			{"name": "ath79_22_03_2", "version": "22.03.2", "target": "ath79/nand", "arch": "mips_24kc"} ]'

	return 0
}

getinfo() {
	validate_section_config "$SCONFIG" define_global
	local rawhtml stables releases targets pkgarchs download_url="${GLOBAL_download_url:-$DOWNLOAD_URL}"

	# Versions
	rawhtml="$(curl --connect-timeout 10 --retry 3 -sSL "$download_url/")"
	stables="$( \
	echo "$rawhtml" | sed -n '/Stable Release/,/Development Snapshots/p' \
	| sed -n '/<ul>/,/<\/ul>/p' | grep 'OpenWrt' \
	| sed -E "s|.+\breleases/([^/]+)/.+|\1|g" \
	)"
	releases="$( \
	echo "$rawhtml" | sed -n '/Release Archive/,/\$/p' \
	| sed -n '/<ul>/,/<\/ul>/p' | grep 'OpenWrt' \
	| sed -E "s|.+\breleases/([^/]+)/.+|\1|g" \
	)"
	mkdir -p "${RELEASES_LIST%/*}" 2>/dev/null
	echo -e "Releases:"
	echo -e "$stables\n$releases"
	echo -e "$stables\n$releases" > "$RELEASES_LIST"

	# Targets
	for stable in $stables; do
		rawhtml="$(curl --connect-timeout 10 --retry 3 -sSL "$download_url/$URLHREF_RELEASES/$stable/$URLHREF_VERS_TARGETS/")"
		targets="$( \
		echo "$rawhtml" \
		| grep -E '<a href=.+\d+:\d+' \
		| sed -E "s|.+\bhref=\"([^/]+)/.+|\1|g" \
		)"
		## subTargets
		fulltargets="$( \
		for target in $targets; do
			subtargets="$(curl -sL "$download_url/$URLHREF_RELEASES/$stable/$URLHREF_VERS_TARGETS/$target/" \
			| grep -E '<a href=.+\d+:\d+' \
			| sed -E "s|.+\bhref=\"([^/]+)/.+|\1|g" \
			)"
			for subtarget in $subtargets; do sed "s|^|$target/|" <<< "$subtarget"; done
		done \
		)"
		fulltargetss="$(echo -e "$fulltargetss\n$fulltargets" | sort -u | grep -v '^$')"
	done
	mkdir -p "${TARGETS_LIST%/*}" 2>/dev/null
	echo "Targets:"
	echo "$fulltargetss"
	echo "$fulltargetss" > "$TARGETS_LIST"

	# Archs
	for stable in $stables; do
		rawhtml="$(curl --connect-timeout 10 --retry 3 -sSL "$download_url/$URLHREF_RELEASES/$stable/$URLHREF_VERS_PACKAGES/")"
		pkgarchs="$( \
		echo "$rawhtml" \
		| grep -E '<a href=.+\d+:\d+' \
		| sed -E "s|.+\bhref=\"([^/]+)/.+|\1|g" \
		)"
		pkgarchss="$(echo -e "$pkgarchss\n$pkgarchs" | sort -u | grep -v '^$')"
	done
	mkdir -p "${PKGARCHS_LIST%/*}" 2>/dev/null
	echo "PKGArchs:"
	echo "$pkgarchss"
	echo "$pkgarchss" > "$PKGARCHS_LIST"
}

gethome() {
	home_url="${1:-$(uci -q get $CONFIG_NAME.$SCONFIG.home_url)}"
	home_url="${home_url:-$DEF_HOMEURL}"
	home_path="/www/$home_url"
}

checkln() {
	gethome

	# clean up old symlink
	ls -l /www | grep "\-> $MNTPKGS" | grep -v " $home_url -> $MNTPKGS" | sed -En "s,.+ ('.+'|\S+) -> ${MNTPKGS}$,'/www/\1',p" | xargs rm -f
	# show occupied
	find /www/* ! -type l -maxdepth 0 | sed "s|.*/||g"
}

symln() {
	gethome "$1"

	# make mount dir
	[ -e "$home_path" ] || { ln -s "$MNTPKGS" "$home_path" 2>/dev/null; ln -s "$RESULTPATH" "$home_path/results" 2>/dev/null; return 0; }
	[ -L "$home_path" ] || { >&2 echo "The Name $home_url is already used, please use another name"; return 1; }
	[ -n "$(ls -l "$home_path" | grep " $home_path -> $MNTPKGS")" ] || { >&2 echo "The Name $home_url is already used, please use another name"; return 1; }
	return 0
}

setcron() {
	local cron="$1" exist=$(cat "$CRONTABS" | sed -n "/\/etc\/init.d\/packagesync start/=")

	if [ -n "$cron" ]; then
		[ -n "$exist" ] && sed -i "/\/etc\/init.d\/packagesync start/d" "$CRONTABS"
		sed -i "\$a$cron /etc/init.d/packagesync start" "$CRONTABS"
	else
		[ -n "$exist" ] && sed -i "/\/etc\/init.d\/packagesync start/d" "$CRONTABS"
	fi
}

cleanup_regex() {
	[ "$2" == "0" ] || { >&2 echo "section $1 validation failed"; return 1; }
	targets="${targets:+$targets|}/$version/$URLHREF_VERS_TARGETS/$target\b"
	packages="${packages:+$packages|}/$version/$URLHREF_VERS_PACKAGES\b"
	pkgarchs="${pkgarchs:+$pkgarchs|}/$URLHREF_PACKAGES_PREFIX${version%\.*}/$pkgarch\b"
}

cleanup() {
	local autorm="$1"
	gethome

	local count targets packages pkgarchs
	[ -d "$home_path/$URLHREF_RELEASES" ] || return 1

	config_foreach validate_section_release $RELEASE cleanup_regex || return $?

	#count=$(uci -q show $CONFIG_NAME|grep "=$RELEASE"|sed -E "s|.+@$RELEASE\[(\d+)\].+|\1|"|tail -n1)
	#
	#local ucivv="version target pkgarch"
	#for i in $(seq 0 $count); do
	#	for _var in $ucivv; do
	#		eval "local $_var=\$(uci -q get $CONFIG_NAME.@$RELEASE[$i].$_var)"
	#	done
	#	targets="${targets:+$targets|}/$version/$URLHREF_VERS_TARGETS/$target\b"
	#	packages="${packages:+$packages|}/$version/$URLHREF_VERS_PACKAGES\b"
	#	pkgarchs="${pkgarchs:+$pkgarchs|}/$URLHREF_PACKAGES_PREFIX${version%\.*}/$pkgarch\b"
	#done
	#echo "$targets"
	#echo "$packages"
	#echo "$pkgarchs"

	local rm_path="$( \
	find $home_path/$URLHREF_RELEASES/* -type d -o -type l -maxdepth 3 | grep -Ev "$targets" | grep -Ev "$packages" | grep -Ev "$pkgarchs" \
	| grep -E "(/\d+\.\d+[^/]*/($URLHREF_VERS_PACKAGES|$URLHREF_VERS_TARGETS/[^/]+/[^/]+)\$|/${URLHREF_PACKAGES_PREFIX}\d+\.\d+/[^/]+\$)" \
	)"
	sed "s|^/|rm -rf '/|g;s|$|'|g" <<< "$rm_path"
	[ -z "$autorm" ] && return 0 || echo "$rm_path" | xargs rm -rf

}

restart() {
	start
}

boot() {
	mkdir -p "$RESULTPATH" 2>/dev/null
	gethome
	if [ -e "$home_path" ]; then
		if [ -L "$home_path" -a "$(readlink "$home_path")" = "$MNTPKGS" ]; then
			sleep 0
		else
			uci set $CONFIG_NAME.$SCONFIG.home_url="$DEF_HOMEURL"
			uci commit $CONFIG_NAME
			ln -s "$MNTPKGS" "$DEF_HOMEPATH"
		fi
	else
		ln -s "$MNTPKGS" "$home_path"
	fi
	return 0
}

service_triggers() {
	procd_add_reload_trigger "$CONFIG_NAME"
}
