# Tiny Cloud - IMDS connection configuration
# vim:set filetype=sh:
# shellcheck shell=sh

load_imds_connection() {
	local connection_file first_endpoint

	unset -f provider_imds_targets 2>/dev/null || true
	connection_file="$LIBDIR/tiny-cloud/cloud/$CLOUD/imds-connection"
	if [ -f "$connection_file" ]; then
		. "$connection_file"
	fi

	: "${IMDS_TRANSPORT:=http}"
	[ "${IMDS_DEFAULT_ENDPOINTS+x}" = x ] ||
		IMDS_DEFAULT_ENDPOINTS=169.254.169.254

	if [ -n "${IMDS_ENDPOINTS:-}" ]; then
		:
	elif [ -n "${IMDS_ENDPOINT:-}" ]; then
		IMDS_ENDPOINTS="$IMDS_ENDPOINT"
	else
		IMDS_ENDPOINTS="$IMDS_DEFAULT_ENDPOINTS"
	fi

	set -- $IMDS_ENDPOINTS
	first_endpoint="${1:-}"
	if [ -n "$first_endpoint" ]; then
		IMDS_ENDPOINT="$first_endpoint"
	else
		unset IMDS_ENDPOINT
	fi
}

imds_targets() {
	case "$IMDS_TRANSPORT" in
		http)
			[ -n "$IMDS_ENDPOINTS" ] &&
				printf '%s\n' "$IMDS_ENDPOINTS"
			;;
		seed)
			if type provider_imds_targets 2>/dev/null |
					grep -q -w function; then
				provider_imds_targets
			fi
			;;
	esac
}

imds_host_port() {
	local authority default_port host port target="$1"

	case "$target" in
		http://*)
			authority="${target#http://}"
			default_port=80
			;;
		https://*)
			authority="${target#https://}"
			default_port=443
			;;
		file:*|local:*|/*) return 1;;
		*)
			authority="$target"
			default_port=80
			;;
	esac
	authority="${authority%%[/?#]*}"
	authority="${authority##*@}"

	case "$authority" in
		\[*\]:*)
			host="${authority#\[}"
			host="${host%%\]*}"
			port="${authority##*\]:}"
			;;
		\[*\])
			host="${authority#\[}"
			host="${host%\]}"
			port="$default_port"
			;;
		*:*)
			host="${authority%:*}"
			port="${authority##*:}"
			;;
		*)
			host="$authority"
			port="$default_port"
			;;
	esac
	[ -n "$host" ] || return 1
	printf '%s\n%s\n' "$host" "$port"
}

imds_target_families() {
	local host old_ifs octet

	set -- $(imds_host_port "$1") || return
	host="$1"
	case "$host" in
		*:*) printf '6\n';;
		*[!0-9.]*) printf '4\n6\n';;
		*)
			old_ifs=$IFS
			IFS=.
			set -- $host
			IFS=$old_ifs
			[ "$#" -eq 4 ] || return
			for octet; do
				[ -n "$octet" ] &&
					[ "$octet" -le 255 ] 2>/dev/null || return
			done
			printf '4\n'
			;;
	esac
}

imds_target_has_route() {
	local family host target="$1"

	set -- $(imds_host_port "$target") || return 1
	host="$1"
	family=$(imds_target_families "$target") || return 1
	case "$family" in
		6) ip -6 route get "$host" >/dev/null 2>&1;;
		4) ip route get "$host" >/dev/null 2>&1;;
		*) return 1;;
	esac
}

imds_has_route() {
	local target targets

	targets=$(imds_targets) || return 1
	for target in $targets; do
		imds_target_has_route "$target" && return
	done
	return 1
}

imds_families() {
	local families family target targets

	targets=$(imds_targets) || return
	for target in $targets; do
		for family in $(imds_target_families "$target"); do
			case " $families " in
				*" $family "*) ;;
				*) families="$families $family";;
			esac
		done
	done
	printf '%s\n' "${families# }"
}
